Function.prototype.IsFunction = true;
String.prototype.IsString = true;
Number.prototype.IsNumber = true;
Boolean.prototype.IsBool = true;
Array.prototype.IsArray = true;
Date.prototype.IsDate = true;
var TypeCode = {
  String: "string",
  Number: "number",
  Object: "object",
  Boolean: "boolean",
  Function: "function",
  Array: "array",
  DateTime: "date",
  Undefined: "undefined",
  Null: null
};

var ValueType = {
  None: null,
  Value: 1,
  Object: 2,
  Array: 3,
  Function: 4
};

/*重载console的方法*/
(function() {
  // console.throwError = function (err) {
  //   console.log(err)
  //   throw new Error(err)
  // }
  // var __consoleLog = console.log
  // console.log = function (msg) {
  //   __consoleLog.call(console, '[{0}] {1}'.format(Date, msg))
  // }
  // var __consoleInfo = console.info
  // console.info = function (msg) {
  //   __consoleInfo.call(console, '[{0}] {1}'.format(Date, msg))
  // }
  // var __consoleWarn = console.warn
  // console.warn = null
  // console.warn = function (msg) {
  //   __consoleWarn.call(console, '[{0}] {1}'.format(Date, msg))
  // }
  //var __consoleError = console.error;
  //console.error = null;
  //console.error = function ( msg )
  //{
  //    __consoleError.call( console, "[{0}] {1}".format( Date, msg ) );
  //};
})();

/****************************************Object扩展****************************************/
(function() {
  Object.callDebugger = function() {
    debugger;
  };

  Object.GetType = function(obj) {
    /// <summary>获取对象的类型</summary>
    /// <param name="obj" type="Object">需要判断类型的对象</param>
    /// <returns type="String" />
    var typeCode;
    if (typeof obj == "undefined") {
      return TypeCode.Undefined;
    }
    if (obj == null) {
      return TypeCode.Null;
    }
    if (obj.IsArray) {
      return TypeCode.Array;
    }
    if (obj.IsDate) {
      return TypeCode.DateTime;
    }
    typeCode = typeof obj;

    if (obj instanceof Function || obj.IsFunction) {
      return TypeCode.Function;
    }

    if (obj instanceof Number) {
      return TypeCode.Number;
    }

    if (obj instanceof Array) {
      return TypeCode.Array;
    }

    if (obj instanceof Date || obj.IsDate) {
      return TypeCode.DateTime;
    }

    if (obj instanceof Boolean) {
      return TypeCode.Boolean;
    }

    if (typeCode != TypeCode.Object) {
      return typeCode;
    }
    return TypeCode.Object;
  };

  Object.toQueryString = function(obj) {
    let params = new URLSearchParams();
    Object.keys(obj).forEach(key => {
      params.set(key, obj[key]);
    });
    return params.toString();
  };

  Object.parseJSON = function(obj) {
    /// <summary>将JSON字符串转换成对象</summary>
    if (Object.isNull(obj)) {
      return null;
    }
    if (obj.IsString) {
      return obj;
    }
    return JSON.stringify(obj);
  };

  Object.clone = function(obj, cloneFunc) {
    /// <summary>深度克隆一个对象</summary>
    /// <param name="obj" type="Object">需要被克隆的对象</param>
    /// <param name="cloneFunc" type="Boolean">是否需要克隆对象的自定义函数</param>
    if (obj == null) {
      return null;
    }
    if (!cloneFunc) {
      return JSON.parse(JSON.stringify(obj));
    }
    //如果要将对象的自定义函数也克隆，则需要自己实现
    var result = JSON.parse(JSON.stringify(obj));
    var _cloneFuncs = function(target, item) {
      //克隆对象的自定义函数
      Object.keys(item).forEach(function(key) {
        var val = item[key];
        if (Object.isNotNull(val)) {
          if (
            val.IsString ||
            val.IsDate ||
            val.IsBool ||
            val.IsArray ||
            val.IsNumber
          ) {
            return;
          } else if (val.IsFunction) {
            target[key] = val;
          } else {
            _cloneFuncs(target[key], val);
          }
        }
      });
    };
    _cloneFuncs(result, obj);
    return result;
  };

  Object.tableToObjects = function(dataTable) {
    /// <summary>将DataTable类型的数据转换成Object数组</summary>
    /// <param name="dataTable" type="DataTable">数据表格的JS对象</param>
    /// <returns type="List&lt;Object&gt;" />
    if (
      !dataTable ||
      !dataTable.rows ||
      !dataTable.rows.length ||
      !dataTable.columns ||
      !dataTable.columns.length
    ) {
      return null;
    }
    var list = [];
    var rowLength = dataTable.rows.length;
    var columnLength = dataTable.columns.length;
    var funBody = ["var rowObj = {};"];
    dataTable.columns.forEach(function(col, idx) {
      funBody.push("rowObj['{0}'] = rowData[{1}];".format(col, idx));
    });

    funBody.push("return rowObj;");
    var funCreateRow = new Function("rowData", funBody.join("\r\n"));
    for (var i = 0; i < rowLength; i++) {
      var rowData = dataTable.rows[i];
      if (rowData) {
        list.push(funCreateRow(rowData));
      } else {
        list.push(null);
      }
    }
    return list;
  };

  Object.setValue = function(target, expression, value) {
    /// <summary>设置指定对象指定属性的值</summary>
    /// <param name="target" type="Object">指定目标对象</param>
    /// <param name="expression" type="String">属性表达式, 示例: target.Property1.Property2</param>
    /// <param name="value" type="Object">值对象(Object, String, Number, DateTime……)</param>
    /// <returns type="void" />
    try {
      var objTmp = target;
      var expArr = expression.split(".");
      var k = expArr.length - 1;
      for (var i = 0; i < k; i++) {
        var obj;
        obj = objTmp[expArr[i]];
        if (obj == null || typeof obj == "undefined") {
          objTmp = objTmp[expArr[i]] = {};
        } else {
          objTmp = obj;
        }
      }
      objTmp[expArr.last()] = value;
    } catch (e) {}
  };

  Object.getValue = function(target, expression) {
    /// <summary>获取指定对象指定的属性值</summary>
    /// <param name="taregt" type="Object">要获取属性值的目标对象</param>
    /// <param name="expression" type="String">属性表达式，比如：ChildNode.Name</param>
    /// <returns type="Object" />
    if (!target) {
      return null;
    }
    var objTmp = target;
    var value = target[expression];
    if (typeof value != "undefined") {
      return value;
    }
    var expArr = expression.split(".");
    for (var i = 0, k = expArr.length - 1; i <= k; i++) {
      objTmp = objTmp[expArr[i]];
      if (objTmp == null || typeof objTmp == "undefined") {
        return null;
      }
    }
    return objTmp;
  };

  Object.isValidNumber = function(val) {
    /// <summary>判断一个对象是否为有效数字</summary>
    if (Object.isNullOrEmpty(val)) {
      return false;
    }
    if (val.IsNumber) {
      return val.isValidNumber();
    } else if (val.IsString) {
      var num = parseInt(val);
      if (num.toString() == val) {
        return num.isValidNumber();
      }
    }
    return false;
  };

  Object.toSize = function(val) {
    /// <summary>获取数字的HTML尺寸单位，如果是纯数字，则加伤px后缀</summary>
    if (Object.isNullOrEmpty(val)) {
      return null;
    }
    if (Object.isValidNumber(val)) {
      val = val + "px";
    }
    return val;
  };

  Object.ifNull = function(target, val1, val2, val3, valN) {
    /// <summary>返回第一个参数不为null的值</summary>
    if (!Object.isNull(target)) {
      return target;
    }
    for (var i = 1; i < arguments.length; i++) {
      if (arguments[i] != null) {
        return arguments[i];
      }
    }
    return target;
  };

  Object.isNull = function(val) {
    /// <summary>判断对象是否为null</summary>
    return val === null || val === undefined;
  };

  Object.isNotNull = function(val) {
    /// <summary>判断对象是否不是空字符串、空数组、空对象（无属性：{}）</summary>
    return !Object.isNull(val);
  };

  Object.isEmpty = function(val) {
    /// <summary>判断对象是否是空字符串、空数组、空对象（无属性：{}）</summary>
    if (
      val == null ||
      val.IsDate ||
      val.IsBool ||
      val.IsNumber ||
      val.IsFunction
    ) {
      return false;
    }
    if (val.IsString) {
      return val.toString().trim() === "";
    } else if (val.IsArray) {
      return val.length == 0;
    }
    return Object.keys(val).length == 0;
  };

  Object.isNotEmpty = function(val) {
    /// <summary>判断对象是否不是空字符串、空数组、空对象（无属性：{}）</summary>
    return !Object.isEmpty(val);
  };

  Object.isNullOrEmpty = function(val) {
    /// <summary>判断一个对象是否为null或者为空字符串、空数组、空对象（无属性：{}）</summary>
    return Object.isNull(val) || Object.isEmpty(val);
  };

  Object.isNotNullOrEmpty = function(val) {
    /// <summary>判断一个对象是否不为null或者不为空字符串、空数组、空对象（无属性：{}）</summary>
    return !Object.isNullOrEmpty(val);
  };

  Object.ifNullOrEmpty = function(target, val1, val2, val3, valN) {
    /// <summary>返回第一个参数不为null的值</summary>
    if (!Object.isNullOrEmpty(target)) {
      return target;
    }
    for (var i = 1; i < arguments.length; i++) {
      var val = arguments[i];
      if (!Object.isNullOrEmpty(val)) {
        return arguments[i];
      }
    }
    return target;
  };

  Object.Is = function(value) {
    /// <summary>将value值转换成Boolean值</summary>
    /// <param name="value" type="Object">一个对象</param>
    /// <returns type="Boolean" />
    if (Object.isUndefined(value) || value == null) {
      return false;
    }
    if (value.toString().toLowerCase() == "true") {
      return true;
    }
    if (value.toString().toLowerCase() == "false") {
      return false;
    }
    if (parseInt(value) > 0) {
      return true;
    }
    return false;
  };

  Object.isUndefined = function(obj) {
    return typeof obj == "undefined";
  };

  /**
   * 混合对象的属性，将后面对象中的属性混合到目标对象中，如果目标对象中属性值存在，则不进行混合
   * @param {Object} target
   * @param {Object} src1
   * @param {Object} src2
   */
  Object.merge = function(target, src1, src2) {
    var funCheck = function(key, targetValue, srcValue) {
      return targetValue == null;
    };
    var lastArg = arguments[arguments.length - 1];
    if (lastArg && lastArg.IsFunction) {
      funCheck = lastArg;
    }
    target = target || {};
    for (var i = 1; i < arguments.length; i++) {
      var srcObject = arguments[i];
      if (srcObject && !srcObject.IsFunction) {
        Object.eachKey(srcObject, function(key) {
          var targetValue = target[key];
          var srcValue = srcObject[key];
          if (funCheck(key, targetValue, srcValue)) {
            target[key] = srcValue;
          }
        });
      }
    }
    return target;
  };

  /**
   * 混合对象的属性，将后面对象中的有效(不为null、""、[]对象)属性混合到目标对象中
   * @param {Object} target
   * @param {Object} src1
   * @param {Object} src2
   */
  Object.mergeValue = function(target, src1, src2) {
    target = target || {};
    for (var i = 1; i < arguments.length; i++) {
      var srcObject = arguments[i];
      if (srcObject && !srcObject.IsFunction) {
        Object.eachKey(srcObject, function(key) {
          var srcValue = srcObject[key];
          if (Object.isNotNullOrEmpty(srcValue)) {
            target[key] = srcValue;
          }
        });
      }
    }
    return target;
  };

  Object.isObject = function(val) {
    if (val === null || val === undefined) {
      return false;
    }
    return (
      !val.IsString &&
      !val.IsDate &&
      !val.IsNumber &&
      !val.IsBool &&
      !val.IsArray &&
      !val.IsFunction
    );
  };

  Object.isValueType = function() {
    if (val === null || val === undefined) {
      return false;
    }
    return val.IsString || val.IsDate || val.IsNumber || val.IsBool;
  };

  Object.getValueType = function(val) {
    if (val === null || val === undefined) {
      return ValueType.None;
    }
    if (val.IsString || val.IsDate || val.IsNumber || val.IsBool) {
      return ValueType.Value;
    }
    if (val.IsArray) {
      return ValueType.Array;
    }
    if (val.IsFunction) {
      return ValueType.Function;
    }
    return ValueType.Object;
  };

  /**
   * 递归继承属性，只复制“值”类型的属性，Object、Array不覆盖
   * @param {*} target
   */
  Object.extends = function(target) {
    if (arguments.length <= 1) {
      return target;
    };
    function extendsObjectValues(targetObj, srcObj) {
      Object.keys(srcObj).forEach(key => {
        let srcVal = srcObj[key];
        let valType = Object.getValueType(srcVal);
        switch (valType) {
          case ValueType.Value:
          case ValueType.Function:
            targetObj[key] = srcVal;
            break;

          case ValueType.Object:
          case ValueType.Array:
            let targetVal = targetObj[key];
            if (targetVal === null || targetVal === undefined) {
              targetVal = targetObj[key] =
                valType === ValueType.Object ? {} : [];
            }
            extendsObjectValues(targetVal, srcVal);
            break;
        }
      });
    };
    let args = Array.prototype.concat.apply([], arguments);
    args.shift(); //移除target参数
    args.forEach(obj => {
      if (Object.isObject(obj)) {
        extendsObjectValues(target, obj);
      }
    });
    return target;
  };

  if (!Object.assign) {
    Object.assign = function(target) {
      /// <summary>复制属性到target对象</summary>
      if (target) {
        for (var i = 1; i < arguments.length; i++) {
          var source = arguments[i];
          if (source) {
            Object.eachKey(source, function(key) {
              target[key] = source[key];
            });
          }
        }
      }
      return target;
    };
  }

  if (!Object.keys) {
    Object.keys = function(obj) {
      /// <summary>获取对象的所有自身属性，不包括继承链的属性</summary>
      var keys = [];
      if (obj == null || Object.isUndefined(obj)) {
        return keys;
      }
      for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
          keys.push(key);
        }
      }
      return keys;
    };
  }

  Object.eachKey = function(obj, callback, thisObj) {
    /// <summary>循环对象自身的每一个属性，继承链上的不循环</summary>
    /// <param name="obj" type="Object">对象</param>
    /// <param name="callback" type="Function">回调函数</param>
    Object.keys(obj).forEach(callback, thisObj);
  };

  Object.GUID = function() {
    /// <summary>获取一个全局唯一ID：GUID</summary>
    return [
      location.href,
      Date.Now().getTime(),
      navigator.userAgent,
      Math.random()
    ]
      .join("_")
      .md5();
  };
})();

/****************************************Number扩展****************************************/
(function() {
  Number.prototype.format = function(
    precision,
    splitChar,
    intervalNum,
    ignoreChar,
    resetIgnoreCounter,
    reverse
  ) {
    /// <summary>将当前数字按指定字符串和指定长度的间隔格式化，比如 13888888888 按“ ”字符间隔4个长度格式化成138 8888 8888</summary>
    /// <param name="precision" type="Int32">数字的精度，默认2位</param>
    /// <param name="splitChar" type="String">分割字符，默认空格</param>
    /// <param name="intervalNum" type="Number">分割长度，默认4</param>
    /// <param name="ignoreChar" type="String">需要忽略的字符，如果遇到忽略的字符，如果resetIgnoreCounter为true,则长度计数重置为0</param>
    /// <param name="resetIgnoreCounter" type="Boolean">遇到ignoreChar字符时，是否重置间隔计数</param>
    /// <param name="reverse" type="Boolean">是否倒序，默认true</param>
    precision = Object.isValidNumber(precision) ? precision : 0;
    resetIgnoreCounter = Object.ifNullOrEmpty(resetIgnoreCounter, true);
    return this.toFixed(precision).formatWith(splitChar, intervalNum, ".");
  };

  Number.prototype.formatMoney = function(precision) {
    /// <summary>将数字格式化货币格式</summary>
    return this.format(precision, ",", 3, ".");
  };

  Number.prototype.toDateString = function(format) {
    /// <summary>将当前字符串转换成日期类型，并格式化成指定格式的日期字符串</summary>
    if (this <= 0) {
      return "";
    }
    var date = this.toDate();
    return date ? date.toDateString(format) : "";
  };

  Number.prototype.isValidNumber = function() {
    /// <summary>判断当前数字是否为有效数字</summary>
    return !isNaN(this) && isFinite(this);
  };

  Number.prototype.fill = function(count, fillString) {
    /// <summary>将数字的整数部分填充成指定长度的字符串</summary>
    count = count > 0 ? count : 2;
    fillString = fillString || "0";
    var num = parseInt(this);
    var str = num.toString();
    if (str.length >= count) {
      return str;
    }
    var arr = new Array(count - str.length);
    arr.fill(fillString).push(str);
    return arr.join("");
  };

  Number.prototype.toDate = function() {
    return new Date(this);
  };

  Number.toInt32 = function(val, defaultVal) {
    /// <summary>将指定的值转换成整数类型</summary>
    if (val == null || isNaN(val) || !isFinite(val)) {
      return defaultVal;
    }
    return parseInt(val);
  };

  Number.toNumber = function(val, defaultVal) {
    /// <summary>将指定的值转换成数字类型</summary>
    if (val == null || isNaN(val) || !isFinite(val)) {
      return defaultVal;
    }
    return parseFloat(val);
  };

  Number.prototype.split = function() {
    /// <summary>兼容String.prototype.split</summary>
    var str = this.toString();
    return str.split.apply(str, arguments);
  };
})();

/****************************************Array扩展****************************************/
(function() {
  Array.prototype.clone = function() {
    /// <summary>克隆一个数组</summary>
    /// <param name="arr" type="Array">被克隆的数组</param>
    /// <returns type="Array" />
    return Array.prototype.concat.apply([], this);
  };

  //对指定的数组按指定表达式分组
  Array.groupData = function(arrData, expArr, resultObject, groupLevel) {
    /// <summary>对指定的数组按指定表达式分组</summary>
    /// <param name="arrData" type="Array">要分组的数组</param>
    /// <param name="expArr" type="Array">分组表达式</param>
    /// <returns type="Array" />
    if (expArr.length == 0) {
      return;
    }
    if (typeof groupLevel == "undefined") {
      groupLevel = 0;
    }
    if (!resultObject) {
      resultObject = [];
      resultObject.Keys = {};
      resultObject.Root = arrData;
    }

    var arrTmp;
    var expArr1 = expArr.clone();

    expArr1.remove(0);

    for (var key in resultObject) {
      if (Array.groupData.InvalidKeys[key]) {
        continue;
      }
      arrTmp = resultObject[key];
      if (!arrTmp) {
        return resultObject.Root;
      }
      var type = Object.GetType(arrTmp);
      if (type == TypeCode.Function) {
        continue;
      }
      var resultObjectKey = (resultObject[key] = []);
      if (arrTmp.Key) {
        resultObjectKey.Key = arrTmp.Key;
      }
      var fieldName = resultObject.FieldName;
      if (fieldName) {
        resultObjectKey[fieldName] = arrTmp[fieldName];
      }
      resultObjectKey.Keys = {};
      Array.groupDataByExpression(arrTmp, expArr[0], resultObjectKey);
      resultObjectKey.FieldName = expArr[0].FieldName;
      resultObjectKey.FieldAlias = expArr[0].FieldAlias
        ? expArr[0].FieldAlias
        : expArr[0].FieldName;
      resultObjectKey.GroupLevel = groupLevel;
      groupLevel++;
      Array.groupData(resultObjectKey, expArr1, resultObjectKey, groupLevel);
      groupLevel--;
    }
    if (resultObject.Root) {
      resultObject.Root.IsGroupData = true;
    }
    return resultObject.Root;
  };

  Array.groupData.InvalidKeys = {
    Key: 1,
    Keys: 1,
    IsArray: 1,
    FieldName: 1,
    FieldAlias: 1,
    GroupLevel: 1,
    OnChangedHandlers: 1,
    EventTypes: 1
  };

  /*
        FieldName
        FieldAlias
    */
  Array.groupDataByExpression = function(arrData, exp, resultObject) {
    var fieldName;
    if (!resultObject) {
      resultObject = [];
    }
    fieldName = exp.FieldName;
    for (var j = 0; j < arrData.length; j++) {
      var obj;
      var fieldValue;
      var arr = null;

      obj = arrData[j];
      var type = Object.GetType(obj);
      if (!String.IsNullOrEmpty(fieldName)) {
        if (fieldName.IsFunction) {
          fieldValue = fieldName(obj);
        } else {
          fieldValue = obj[fieldName];
        }
      } else {
        fieldValue = obj;
      }
      if (!resultObject.Keys) {
        resultObject.Keys = {};
      }
      var index = resultObject.Keys[fieldValue];
      if (index >= 0) {
        arr = resultObject[index];
      }
      if (!arr) {
        arr = [];
        if (exp.FieldAlias) {
          arr[exp.FieldAlias] = fieldValue;
        }
        arr.Key = fieldValue;
        resultObject.push(arr);
        resultObject.Keys[fieldValue] = resultObject.length - 1;
      }
      arr.push(obj);
    }
    return resultObject;
  };

  Array.prototype.groupData = function(expArr, aggregates, resultObject) {
    /// <summary>对指定的数组按指定表达式分组</summary>
    /// <param name="expArr" type="Array">分组表达式</param>
    /// <param name="aggregates" type="Object">总计表达式</param>
    /// <returns type="Array" />
    return Array.groupData(this, expArr, aggregates, resultObject);
  };

  Array.prototype.addSingle = function() {
    /// <summary>添加唯一的元素</summary>
    if (arguments.length > 0) {
      for (var i = 0; i < arguments.length; i++) {
        var item = arguments[i];
        if (!this.contains(item)) {
          this.push(item);
        }
      }
    }
    return this;
  };

  Array.prototype.forEachReverse = function(func, thisObj) {
    /// <summary>逆向循环数组</summary>
    for (var i = this.length - 1; i >= 0; i--) {
      func && func.call(thisObj, this[i], i);
    }
    return this;
  };

  Array.prototype.joinValue = function(field, separator, ignoreEmpty) {
    /// <summary>循环数组的每一个并拼接为一个字符串</summary>
    /// <param name="field" type="String|Function">指定属性名称或回调函数</param>
    /// <param name="separator" type="String">分割字符串</param>
    if (this.length == 0) {
      return "";
    }
    separator = Object.ifNull(separator, "");
    var func = null;
    if (field && field.IsFunction) {
      func = field;
    } else {
      func = new Function(
        "item",
        "\
                if ( Object.isNull( item ) )\
                    {\
                        return '';\
                    };\
                    return item.{{0}};".format(
          Object.ifNullOrEmpty(field, "toString()")
        )
      );
    }
    if (!ignoreEmpty) {
      return this.map(func, this).join(separator);
    }
    var result = [];
    this.forEach(function(item) {
      item = func(item);
      if (Object.isNotNullOrEmpty(item)) {
        result.push(item);
      }
    });
    return result.join(separator);
  };

  Array.prototype.contains = function(find) {
    /// <summary>数组是否包含find指定的元素，find可为值对象或Function回调</summary>
    if (this.length == 0) {
      return false;
    }
    if (find && find.IsFunction) {
      return this.findIndex(find, this) >= 0;
    }
    return (
      this.findIndex(function(item) {
        return item == find;
      }, this) >= 0
    );
  };

  Array.prototype.average = function(property) {
    /// <summary>求数组中成员指定属性的平均值</summary>
    /// <param name="property" type="Function|String">指定属性或取值函数</param>
    if (!this.length) {
      return 0;
    }
    return this.sum(property) / this.length;
  };

  Array.prototype.sum = function(property) {
    /// <summary>求数组中成员指定属性的和</summary>
    /// <param name="property" type="Function|String">指定属性或取值函数</param>
    if (!this.length) {
      return 0;
    }
    if (property && property.IsString) {
      property = new Function("data", "return data." + property + ";");
    } else if (!property) {
      property = function(data) {
        return Number(data);
      };
    }
    var sum = 0;
    this.forEach(function(data, idx) {
      try {
        sum += property(data);
      } catch (ex) {}
    });
    return sum;
  };

  Array.prototype.first = function(defaultValue) {
    /// <summary>获取数据的第一个</summary>
    return Object.ifNull(this[0], defaultValue);
  };

  Array.prototype.last = function(defaultValue) {
    /// <summary>获取数据的最后一个</summary>
    return Object.ifNull(this[this.length - 1], defaultValue);
  };

  Array.prototype.insert = function(idx, val) {
    /// <summary>在数组的指定索引位置插入一个值</summary>
    this.splice(idx, 0, val);
    return this;
  };

  Array.prototype.enqueue = function(val) {
    /// <summary>将一个值入队</summary>
    return this.insert(0, val);
  };

  Array.prototype.remove = function(idx) {
    /// <summary>删除指定索引的项</summary>
    this.splice(idx, 1);
    return this;
  };

  Array.prototype.removeFirst = function() {
    /// <summary>移除第一项并返回数组</summary>
    this.shift();
    return this;
  };

  Array.prototype.removeLast = function() {
    /// <summary>移除最后一项并返回数组</summary>
    this.pop();
    return this;
  };

  Array.prototype.removeValue = function(val, count) {
    /// <summary>删除指定值的项</summary>
    /// <param name="val" type="Object|Function">要删除的项或判定函数</param>
    /// <param name="count" type="Int32">要删除的数量</param>
    var func =
      val && val.IsFunction
        ? val
        : function(data) {
            return data === val;
          };
    if (count <= 0) count = this.length;
    var _removeCounter = 0;
    for (i = this.length - 1; i >= 0; i--) {
      if (func(this[i])) {
        this.splice(i, 1);
        _removeCounter++;
        if (_removeCounter >= count) {
          break;
        }
      }
    }
    return this;
  };

  Array.prototype.clear = function() {
    /// <summary>清空数组</summary>
    this.splice(0, this.length);
    return this;
  };

  Array.prototype.toObject = function(field, targetObj) {
    /// <summary>将数值按指定属性值或取值函数转换成键值对象</summary>
    /// <param name="field" type="String|Function">指定属性名称或取值函数</param>
    /// <param name="targetObj" type="Object">目标键值对象，如果为null，则创建一个{}</param>
    targetObj = targetObj || {};
    if (!field) {
      field = function(data) {
        return data.toString().trim();
      };
    } else if (field.IsString) {
      var _field = field;
      field = function(data) {
        return data[_field];
      };
    }
    this.forEach(function(data) {
      targetObj[field(data)] = data;
    });
    return targetObj;
  };

  if (!Array.prototype.find) {
    Array.prototype.find = function(func, thisObj) {
      /// <summary>按指定回调函数的返回值查找元素</summary>
      /// <param name="func" type="Function">回调函数</param>
      if (func && func.IsString) {
        func = new Function(item, "return " + func);
      }
      for (var i = 0; i < this.length; i++) {
        if (func.call(thisObj, this[i])) {
          return this[i];
        }
      }
      return null;
    };
  }

  if (!Array.prototype.fill) {
    Array.prototype.fill = function(val, start, end) {
      /// <summary>填充数组</summary>
      /// <param name="val" type="Object">要填充的值</param>
      /// <param name="start" type="Int32">开始索引，默认0</param>
      /// <param name="end" type="Int32">结束索引，默认全部</param>
      if (!(start >= 0)) {
        start = 0;
      }
      if (!(end > 0)) {
        end = this.length;
      }
      for (var i = start; i < end; i++) {
        this[i] = val;
      }
      return this;
    };
  }

  Array.prototype.split = function() {
    /// <summary>兼容String.prototype.split</summary>
    return this;
  };
})();

/****************************************Date扩展****************************************/
(function() {
  Date.IsDate = function() {
    /// <summary>判断一个对象是否是日期对象</summary>
    /// <returns type="Boolean" />
    return date.ToDate() != null;
  };

  Date.DATE_FORMAT_OPTIONS = [
    {
      handler: function() {
        return this.getFullYear();
      },
      regExp: new RegExp("(YYYY|yyyy)")
    },
    {
      handler: function() {
        var year = this.getFullYear();
        return (year - parseInt(year / 100) * 100).fill();
      },
      regExp: new RegExp("(YY|yy)")
    },
    {
      handler: function() {
        return (this.getMonth() + 1).fill();
      },
      regExp: new RegExp("(MM)")
    },
    {
      handler: function() {
        return this.getDate().fill();
      },
      regExp: new RegExp("(dd|DD)")
    },
    {
      handler: function() {
        return this.getHours().fill();
      },
      regExp: new RegExp("(HH|hh)")
    },
    {
      handler: function() {
        return this.getMinutes().fill();
      },
      regExp: new RegExp("(mm)")
    },
    {
      handler: function() {
        return this.getSeconds().fill();
      },
      regExp: new RegExp("(ss)")
    },
    {
      handler: function() {
        return Math.floor((this.getMonth() + 3) / 3).fill();
      },
      regExp: new RegExp("(QQ)")
    },
    {
      handler: function() {
        return this.getMilliseconds();
      },
      regExp: new RegExp("(SS)")
    }
  ];

  Date.DATE_FORMAT_CACHES = {};

  Date.toString = function(format) {
    return new Date().toString(format);
  };

  Date.toTimeString = function(format) {
    return new Date().toString(format || "HH:mm:ss SS");
  };

  Date.Now = function() {
    return new Date();
  };

  Date.prototype.toString = function(format) {
    /// <summary>格式化日期为指定格式的字符串</summary>
    /// <param name="format" type="String">格式字符串，默认为：yyyy-MM-dd HH:mm:ss</param>
    format = format || "yyyy-MM-dd HH:mm:ss";
    var cacheHandler = Date.DATE_FORMAT_CACHES[format];
    if (!cacheHandler) {
      var handlers = [];
      Date.DATE_FORMAT_OPTIONS.forEach(function(opt, idx) {
        if (opt.regExp.test(format)) {
          handlers.push(idx);
        }
      });
      Date.DATE_FORMAT_CACHES[format] = cacheHandler = new Function(
        "date, format",
        "\r\n\
                {{0}}.forEach( function ( idx )\r\n\
                {\r\n\
                    var opt = Date.DATE_FORMAT_OPTIONS[idx];\r\n\
                    format = format.replace( opt.regExp, opt.handler.call( date ) );\r\n\
                } );\r\n\
                return format;\r\n".format(
          JSON.stringify(handlers)
        )
      );
    }
    return cacheHandler(this, format);
  };

  Date.prototype.split = function() {
    return this.toString().split.apply(this, arguments);
  };

  Date.prototype.toDateString = function(format) {
    /// <summary>将当前日期转换成日期格式：yyyy年MM月dd日</summary>
    /// <param name="format" type="String">格式字符串，默认为：yyyy年MM月dd日</param>
    format = format || "yyyy年MM月dd日";
    return this.toString(format);
  };

  Date.prototype.fullQuarter = function() {
    /// <summary>获取当前日期所处的季度</summary>
    /// <returns type="String" />
    var year = this.getFullYear();
    return [year, this.quarter().fill(2)].join("");
  };

  Date.prototype.quarter = function() {
    /// <summary>获取当前日期所处的季度</summary>
    /// <returns type="String" />
    var month = this.getMonth() + 1;
    return Math.ceil(month / 3);
  };

  Date.prototype.addDays = function(days) {
    /// <summary>对当前日期增加天数并返回新日期对象</summary>
    /// <param name="months" type="Number">要增加的天数</param>
    /// <returns type="Date" />
    var num = this.getDate();
    num += days;
    var newDate = new Date(this);
    newDate.setDate(num);
    return newDate;
  };

  Date.prototype.addMonths = function(months) {
    /// <summary>对当前日期增加月份数并返回新日期对象</summary>
    /// <param name="months" type="Number">要增加的月份数</param>
    /// <returns type="Date" />
    var num = this.getMonth();
    num += months;
    var newDate = new Date(this);
    newDate.setMonth(num);
    return newDate;
  };

  Date.prototype.addYears = function(years) {
    /// <summary>对当前日期增加年数并返回新日期对象</summary>
    /// <param name="months" type="Number">要增加的年数</param>
    /// <returns type="Date" />
    var num = this.getFullYear();
    num += years;
    var newDate = new Date(this);
    newDate.setFullYear(num);
    return newDate;
  };

  Date.WEEK_NAMES = [
    "星期日",
    "星期一",
    "星期二",
    "星期三",
    "星期四",
    "星期五",
    "星期六"
  ];
  Date.prototype.WeekDayName = function(weekDayNames) {
    /// <summary>获取当前日期对应周名称</summary>
    weekDayNames = Object.ifNull(weekDayNames, Date.WEEK_NAMES);
    return weekDayNames[this.getDay()];
  };

  Date.prototype.weekFirstDay = function() {
    /// <summary>获取当前日期所处的周的周一的日期</summary>
    /// <returns type="Date" />
    var day = this.getDay();

    if (day == 0) {
      return this.addDays(-6);
    }
    return this.addDays(1 - day)
      .toString("yyyy-MM-dd 00:00")
      .toDate();
  };

  Date.prototype.weekLastDay = function() {
    /// <summary>获取当前日期所处的周的周日的日期</summary>
    /// <returns type="Date" />
    var day = this.getDay();

    if (day == 0) {
      return this;
    }
    return this.addDays(7 - day);
  };

  Date.prototype.monthFirstDay = function() {
    /// <summary>获取当前日期所处的月的第一天</summary>
    /// <returns type="Date" />
    return this.toString("yyyy-MM-01").toDate();
  };

  Date.prototype.monthLastDay = function() {
    /// <summary>获取当前日期所处的月的最后天</summary>
    /// <returns type="Date" />
    return this.toString("yyyy-MM-01")
      .toDate()
      .addMonths(1)
      .addDays(-1);
  };

  Date.prototype.quarterFirstDay = function() {
    /// <summary>获取当前日期所处的季度的第一天</summary>
    /// <returns type="Date" />
    return [this.getFullYear(), this.quarter().fill(2), "01"].join("-");
  };

  Date.prototype.quarterLastDay = function() {
    /// <summary>获取当前日期所处的季度的最后一天</summary>
    /// <returns type="Date" />
    var quarter = this.quarter();
    var month = quarter * 3;
    var day = quarter == 1 || quarter == 4 ? "31" : "30";
    return [this.getFullYear(), month.fill(2), day.fill(2)].join("-");
  };

  Date.prototype.yearFirstDay = function() {
    /// <summary>获取当前日期所处的年的第一天</summary>
    /// <returns type="Date" />
    return this.toString("yyyy-01-01").toDate();
  };

  Date.prototype.yearLastDay = function() {
    /// <summary>获取当前日期所处的年的最后一天</summary>
    /// <returns type="Date" />
    return this.toString("yyyy-12-31").toDate();
  };

  Date.prototype.toDate = function() {
    return this;
  };

  Date.prototype.diff = function(date2) {
    /// <summary>计算两个日期的差值</summary>
    if (date2 == null) {
      date2 = new Date();
    }
    var diff = new Date(Math.abs(this.getTime() - date2.getTime()));
    var timediff = (timediff2 = diff.getTime());

    var totalYears = Number(timediff2 / 31536000000).toFixed(1);

    var weeks = Math.floor(timediff / 604800000);
    var totalWeeks = Number(timediff2 / 604800000).toFixed(1);
    timediff -= weeks * 604800000;

    var days = Math.floor(timediff / 86400000);
    var totalDays = Number(timediff2 / 86400000).toFixed(1);

    timediff -= days * 86400000;

    var hours = Math.floor(timediff / 3600000);
    var totalHours = Number(timediff2 / 3600000).toFixed(1);

    timediff -= hours * 3600000;

    var mins = Math.floor(timediff / 60000);
    var totalMinutes = parseInt(timediff2 / 60000);

    timediff -= mins * 60000;

    var secs = Math.floor(timediff / 1000);
    var totalSeconds = parseInt(timediff2 / 1000);
    timediff -= secs * 1000;

    var totalMilliSeconds = timediff2;

    var result = {
      StartDate: this,
      EndDate: date2,
      Weeks: weeks,
      Days: days,
      Hours: hours,
      Minutes: mins,
      Seconds: secs,
      TotalYears: totalYears,
      TotalWeeks: totalWeeks,
      TotalDays: totalDays,
      TotalHours: totalHours,
      TotalMinutes: totalMinutes,
      TotalSeconds: totalSeconds,
      TotalMilliSeconds: totalMilliSeconds
    };
    return result;
  };
})();

/****************************************String扩展****************************************/
(function() {
  String.leftTrim = function(s) {
    /// <summary>去掉前导空白字符</summary>
    /// <param name="s" type="String">需要去除前导空白的字符串</param>
    /// <returns type="String" />
    return s.replace(/^\s*/, "");
  };

  String.rightTrim = function(s) {
    /// <summary>去掉后缀空白字符</summary>
    /// <param name="s" type="String">需要去除后缀空白的字符串</param>
    /// <returns type="String" />
    return s.replace(/\s*$/, "");
  };

  String.trim = function(s) {
    /// <summary>去掉前后的空白字符</summary>
    /// <param name="s" type="String">需要去除空白的字符串</param>
    /// <returns type="String" />
    if (typeof s == "undefined") {
      return "";
    }
    var temp = s;
    temp = String.leftTrim(temp);
    temp = String.rightTrim(temp);
    return temp;
  };

  String.trimAll = function(s) {
    return s.replace(/\s*/gi, "");
  };

  String.IsNullOrEmpty = function(str) {
    /// <summary>判断一个字符串对象是否为null或""</summary>
    /// <param name="str" type="String">字符串对象</param>
    /// <returns type="Boolean" />
    if (Object.GetType(str) == TypeCode.Undefined) {
      return true;
    }
    if (str == null) {
      return true;
    }
    str = String.trim(str.toString());
    return str == null || str == "";
  };

  String.IsNotNullOrEmpty = function(str) {
    /// <summary>判断一个字符串对象是否【不】为null或""</summary>
    /// <param name="str" type="String">字符串对象</param>
    /// <returns type="Boolean" />
    return !String.IsNullOrEmpty(str);
  };

  const chineseCharStartIndex = 0x4e00;
  const chineseCharSpellLetterTable =
    "YDYQSXMWZSSXJBYMGCCZQPSSQBYCDSCDQLDYLYBSSJGYZZJJFKCCLZDHWDWZJLJPFYYNWJJTMYHZWZHFLZPPQHGSCYYYNJQYXXGJHHSDSJNKKTMOMLCRXYPSNQSECCQZGGLLYJLMYZZSECYKYYHQWJSSGGYXYZYJWWKDJHYCHMYXJTLXJYQBYXZLDWRDJRWYSRLDZJPCBZJJBRCFTLECZSTZFXXZHTRQHYBDLYCZSSYMMRFMYQZPWWJJYFCRWFDFZQPYDDWYXKYJAWJFFXYPSFTZYHHYZYSWCJYXSCLCXXWZZXNBGNNXBXLZSZSBSGPYSYZDHMDZBQBZCWDZZYYTZHBTSYYBZGNTNXQYWQSKBPHHLXGYBFMJEBJHHGQTJCYSXSTKZHLYCKGLYSMZXYALMELDCCXGZYRJXSDLTYZCQKCNNJWHJTZZCQLJSTSTBNXBTYXCEQXGKWJYFLZQLYHYXSPSFXLMPBYSXXXYDJCZYLLLSJXFHJXPJBTFFYABYXBHZZBJYZLWLCZGGBTSSMDTJZXPTHYQTGLJSCQFZKJZJQNLZWLSLHDZBWJNCJZYZSQQYCQYRZCJJWYBRTWPYFTWEXCSKDZCTBZHYZZYYJXZCFFZZMJYXXSDZZOTTBZLQWFCKSZSXFYRLNYJMBDTHJXSQQCCSBXYYTSYFBXDZTGBCNSLCYZZPSAZYZZSCJCSHZQYDXLBPJLLMQXTYDZXSQJTZPXLCGLQTZWJBHCTSYJSFXYEJJTLBGXSXJMYJQQPFZASYJNTYDJXKJCDJSZCBARTDCLYJQMWNQNCLLLKBYBZZSYHQQLTWLCCXTXLLZNTYLNEWYZYXCZXXGRKRMTCNDNJTSYYSSDQDGHSDBJGHRWRQLYBGLXHLGTGXBQJDZPYJSJYJCTMRNYMGRZJCZGJMZMGXMPRYXKJNYMSGMZJYMKMFXMLDTGFBHCJHKYLPFMDXLQJJSMTQGZSJLQDLDGJYCALCMZCSDJLLNXDJFFFFJCZFMZFFPFKHKGDPSXKTACJDHHZDDCRRCFQYJKQCCWJDXHWJLYLLZGCFCQDSMLZPBJJPLSBCJGGDCKKDEZSQCCKJGCGKDJTJDLZYCXKLQSCGJCLTFPCQCZGWPJDQYZJJBYJHSJDZWGFSJGZKQCCZLLPSPKJGQJHZZLJPLGJGJJTHJJYJZCZMLZLYQBGJWMLJKXZDZNJQSYZMLJLLJKYWXMKJLHSKJGBMCLYYMKXJQLBMLLKMDXXKWYXYSLMLPSJQQJQXYXFJTJDXMXXLLCXQBSYJBGWYMBGGBCYXPJYGPEPFGDJGBHBNSQJYZJKJKHXQFGQZKFHYGKHDKLLSDJQXPQYKYBNQSXQNSZSWHBSXWHXWBZZXDMNSJBSBKBBZKLYLXGWXDRWYQZMYWSJQLCJXXJXKJEQXSCYETLZHLYYYSDZPAQYZCMTLSHTZCFYZYXYLJSDCJQAGYSLCQLYYYSHMRQQKLDXZSCSSSYDYCJYSFSJBFRSSZQSBXXPXJYSDRCKGJLGDKZJZBDKTCSYQPYHSTCLDJDHMXMCGXYZHJDDTMHLTXZXYLYMOHYJCLTYFBQQXPFBDFHHTKSQHZYYWCNXXCRWHOWGYJLEGWDQCWGFJYCSNTMYTOLBYGWQWESJPWNMLRYDZSZTXYQPZGCWXHNGPYXSHMYQJXZTDPPBFYHZHTJYFDZWKGKZBLDNTSXHQEEGZZYLZMMZYJZGXZXKHKSTXNXXWYLYAPSTHXDWHZYMPXAGKYDXBHNHXKDPJNMYHYLPMGOCSLNZHKXXLPZZLBMLSFBHHGYGYYGGBHSCYAQTYWLXTZQCEZYDQDQMMHTKLLSZHLSJZWFYHQSWSCWLQAZYNYTLSXTHAZNKZZSZZLAXXZWWCTGQQTDDYZTCCHYQZFLXPSLZYGPZSZNGLNDQTBDLXGTCTAJDKYWNSYZLJHHZZCWNYYZYWMHYCHHYXHJKZWSXHZYXLYSKQYSPSLYZWMYPPKBYGLKZHTYXAXQSYSHXASMCHKDSCRSWJPWXSGZJLWWSCHSJHSQNHCSEGNDAQTBAALZZMSSTDQJCJKTSCJAXPLGGXHHGXXZCXPDMMHLDGTYBYSJMXHMRCPXXJZCKZXSHMLQXXTTHXWZFKHCCZDYTCJYXQHLXDHYPJQXYLSYYDZOZJNYXQEZYSQYAYXWYPDGXDDXSPPYZNDLTWRHXYDXZZJHTCXMCZLHPYYYYMHZLLHNXMYLLLMDCPPXHMXDKYCYRDLTXJCHHZZXZLCCLYLNZSHZJZZLNNRLWHYQSNJHXYNTTTKYJPYCHHYEGKCTTWLGQRLGGTGTYGYHPYHYLQYQGCWYQKPYYYTTTTLHYHLLTYTTSPLKYZXGZWGPYDSSZZDQXSKCQNMJJZZBXYQMJRTFFBTKHZKBXLJJKDXJTLBWFZPPTKQTZTGPDGNTPJYFALQMKGXBDCLZFHZCLLLLADPMXDJHLCCLGYHDZFGYDDGCYYFGYDXKSSEBDHYKDKDKHNAXXYBPBYYHXZQGAFFQYJXDMLJCSQZLLPCHBSXGJYNDYBYQSPZWJLZKSDDTACTBXZDYZYPJZQSJNKKTKNJDJGYYPGTLFYQKASDNTCYHBLWDZHBBYDWJRYGKZYHEYYFJMSDTYFZJJHGCXPLXHLDWXXJKYTCYKSSSMTWCTTQZLPBSZDZWZXGZAGYKTYWXLHLSPBCLLOQMMZSSLCMBJCSZZKYDCZJGQQDSMCYTZQQLWZQZXSSFPTTFQMDDZDSHDTDWFHTDYZJYQJQKYPBDJYYXTLJHDRQXXXHAYDHRJLKLYTWHLLRLLRCXYLBWSRSZZSYMKZZHHKYHXKSMDSYDYCJPBZBSQLFCXXXNXKXWYWSDZYQOGGQMMYHCDZTTFJYYBGSTTTYBYKJDHKYXBELHTYPJQNFXFDYKZHQKZBYJTZBXHFDXKDASWTAWAJLDYJSFHBLDNNTNQJTJNCHXFJSRFWHZFMDRYJYJWZPDJKZYJYMPCYZNYNXFBYTFYFWYGDBNZZZDNYTXZEMMQBSQEHXFZMBMFLZZSRXYMJGSXWZJSPRYDJSJGXHJJGLJJYNZZJXHGXKYMLPYYYCXYTWQZSWHWLYRJLPXSLSXMFSWWKLCTNXNYNPSJSZHDZEPTXMYYWXYYSYWLXJQZQXZDCLEEELMCPJPCLWBXSQHFWWTFFJTNQJHJQDXHWLBYZNFJLALKYYJLDXHHYCSTYYWNRJYXYWTRMDRQHWQCMFJDYZMHMYYXJWMYZQZXTLMRSPWWCHAQBXYGZYPXYYRRCLMPYMGKSJSZYSRMYJSNXTPLNBAPPYPYLXYYZKYNLDZYJZCZNNLMZHHARQMPGWQTZMXXMLLHGDZXYHXKYXYCJMFFYYHJFSBSSQLXXNDYCANNMTCJCYPRRNYTYQNYYMBMSXNDLYLYSLJRLXYSXQMLLYZLZJJJKYZZCSFBZXXMSTBJGNXYZHLXNMCWSCYZYFZLXBRNNNYLBNRTGZQYSATSWRYHYJZMZDHZGZDWYBSSCSKXSYHYTXXGCQGXZZSHYXJSCRHMKKBXCZJYJYMKQHZJFNBHMQHYSNJNZYBKNQMCLGQHWLZNZSWXKHLJHYYBQLBFCDSXDLDSPFZPSKJYZWZXZDDXJSMMEGJSCSSMGCLXXKYYYLNYPWWWGYDKZJGGGZGGSYCKNJWNJPCXBJJTQTJWDSSPJXZXNZXUMELPXFSXTLLXCLJXJJLJZXCTPSWXLYDHLYQRWHSYCSQYYBYAYWJJJQFWQCQQCJQGXALDBZZYJGKGXPLTZYFXJLTPADKYQHPMATLCPDCKBMTXYBHKLENXDLEEGQDYMSAWHZMLJTWYGXLYQZLJEEYYBQQFFNLYXRDSCTGJGXYYNKLLYQKCCTLHJLQMKKZGCYYGLLLJDZGYDHZWXPYSJBZKDZGYZZHYWYFQYTYZSZYEZZLYMHJJHTSMQWYZLKYYWZCSRKQYTLTDXWCTYJKLWSQZWBDCQYNCJSRSZJLKCDCDTLZZZACQQZZDDXYPLXZBQJYLZLLLQDDZQJYJYJZYXNYYYNYJXKXDAZWYRDLJYYYRJLXLLDYXJCYWYWNQCCLDDNYYYNYCKCZHXXCCLGZQJGKWPPCQQJYSBZZXYJSQPXJPZBSBDSFNSFPZXHDWZTDWPPTFLZZBZDMYYPQJRSDZSQZSQXBDGCPZSWDWCSQZGMDHZXMWWFYBPDGPHTMJTHZSMMBGZMBZJCFZWFZBBZMQCFMBDMCJXLGPNJBBXGYHYYJGPTZGZMQBQTCGYXJXLWZKYDPDYMGCFTPFXYZTZXDZXTGKMTYBBCLBJASKYTSSQYYMSZXFJEWLXLLSZBQJJJAKLYLXLYCCTSXMCWFKKKBSXLLLLJYXTYLTJYYTDPJHNHNNKBYQNFQYYZBYYESSESSGDYHFHWTCJBSDZZTFDMXHCNJZYMQWSRYJDZJQPDQBBSTJGGFBKJBXTGQHNGWJXJGDLLTHZHHYYYYYYSXWTYYYCCBDBPYPZYCCZYJPZYWCBDLFWZCWJDXXHYHLHWZZXJTCZLCDPXUJCZZZLYXJJTXPHFXWPYWXZPTDZZBDZCYHJHMLXBQXSBYLRDTGJRRCTTTHYTCZWMXFYTWWZCWJWXJYWCSKYBZSCCTZQNHXNWXXKHKFHTSWOCCJYBCMPZZYKBNNZPBZHHZDLSYDDYTYFJPXYNGFXBYQXCBHXCPSXTYZDMKYSNXSXLHKMZXLYHDHKWHXXSSKQYHHCJYXGLHZXCSNHEKDTGZXQYPKDHEXTYKCNYMYYYPKQYYYKXZLTHJQTBYQHXBMYHSQCKWWYLLHCYYLNNEQXQWMCFBDCCMLJGGXDQKTLXKGNQCDGZJWYJJLYHHQTTTNWCHMXCXWHWSZJYDJCCDBQCDGDNYXZTHCQRXCBHZTQCBXWGQWYYBXHMBYMYQTYEXMQKYAQYRGYZSLFYKKQHYSSQYSHJGJCNXKZYCXSBXYXHYYLSTYCXQTHYSMGSCPMMGCCCCCMTZTASMGQZJHKLOSQYLSWTMXSYQKDZLJQQYPLSYCZTCQQPBBQJZCLPKHQZYYXXDTDDTSJCXFFLLCHQXMJLWCJCXTSPYCXNDTJSHJWXDQQJSKXYAMYLSJHMLALYKXCYYDMNMDQMXMCZNNCYBZKKYFLMCHCMLHXRCJJHSYLNMTJZGZGYWJXSRXCWJGJQHQZDQJDCJJZKJKGDZQGJJYJYLXZXXCDQHHHEYTMHLFSBDJSYYSHFYSTCZQLPBDRFRZTZYKYWHSZYQKWDQZRKMSYNBCRXQBJYFAZPZZEDZCJYWBCJWHYJBQSZYWRYSZPTDKZPFPBNZTKLQYHBBZPNPPTYZZYBQNYDCPJMMCYCQMCYFZZDCMNLFPBPLNGQJTBTTNJZPZBBZNJKLJQYLNBZQHKSJZNGGQSZZKYXSHPZSNBCGZKDDZQANZHJKDRTLZLSWJLJZLYWTJNDJZJHXYAYNCBGTZCSSQMNJPJYTYSWXZFKWJQTKHTZPLBHSNJZSYZBWZZZZLSYLSBJHDWWQPSLMMFBJDWAQYZTCJTBNNWZXQXCDSLQGDSDPDZHJTQQPSWLYYJZLGYXYZLCTCBJTKTYCZJTQKBSJLGMGZDMCSGPYNJZYQYYKNXRPWSZXMTNCSZZYXYBYHYZAXYWQCJTLLCKJJTJHGDXDXYQYZZBYWDLWQCGLZGJGQRQZCZSSBCRPCSKYDZNXJSQGXSSJMYDNSTZTPBDLTKZWXQWQTZEXNQCZGWEZKSSBYBRTSSSLCCGBPSZQSZLCCGLLLZXHZQTHCZMQGYZQZNMCOCSZJMMZSQPJYGQLJYJPPLDXRGZYXCCSXHSHGTZNLZWZKJCXTCFCJXLBMQBCZZWPQDNHXLJCTHYZLGYLNLSZZPCXDSCQQHJQKSXZPBAJYEMSMJTZDXLCJYRYYNWJBNGZZTMJXLTBSLYRZPYLSSCNXPHLLHYLLQQZQLXYMRSYCXZLMMCZLTZSDWTJJLLNZGGQXPFSKYGYGHBFZPDKMWGHCXMSGDXJMCJZDYCABXJDLNBCDQYGSKYDQTXDJJYXMSZQAZDZFSLQXYJSJZYLBTXXWXQQZBJZUFBBLYLWDSLJHXJYZJWTDJCZFQZQZZDZSXZZQLZCDZFJHYSPYMPQZMLPPLFFXJJNZZYLSJEYQZFPFZKSYWJJJHRDJZZXTXXGLGHYDXCSKYSWMMZCWYBAZBJKSHFHJCXMHFQHYXXYZFTSJYZFXYXPZLCHMZMBXHZZSXYFYMNCWDABAZLXKTCSHHXKXJJZJSTHYGXSXYYHHHJWXKZXSSBZZWHHHCWTZZZPJXSNXQQJGZYZYWLLCWXZFXXYXYHXMKYYSWSQMNLNAYCYSPMJKHWCQHYLAJJMZXHMMCNZHBHXCLXTJPLTXYJHDYYLTTXFSZHYXXSJBJYAYRSMXYPLCKDUYHLXRLNLLSTYZYYQYGYHHSCCSMZCTZQXKYQFPYYRPFFLKQUNTSZLLZMWWTCQQYZWTLLMLMPWMBZSSTZRBPDDTLQJJBXZCSRZQQYGWCSXFWZLXCCRSZDZMCYGGDZQSGTJSWLJMYMMZYHFBJDGYXCCPSHXNZCSBSJYJGJMPPWAFFYFNXHYZXZYLREMZGZCYZSSZDLLJCSQFNXZKPTXZGXJJGFMYYYSNBTYLBNLHPFZDCYFBMGQRRSSSZXYSGTZRNYDZZCDGPJAFJFZKNZBLCZSZPSGCYCJSZLMLRSZBZZLDLSLLYSXSQZQLYXZLSKKBRXBRBZCYCXZZZEEYFGKLZLYYHGZSGZLFJHGTGWKRAAJYZKZQTSSHJJXDCYZUYJLZYRZDQQHGJZXSSZBYKJPBFRTJXLLFQWJHYLQTYMBLPZDXTZYGBDHZZRBGXHWNJTJXLKSCFSMWLSDQYSJTXKZSCFWJLBXFTZLLJZLLQBLSQMQQCGCZFPBPHZCZJLPYYGGDTGWDCFCZQYYYQYSSCLXZSKLZZZGFFCQNWGLHQYZJJCZLQZZYJPJZZBPDCCMHJGXDQDGDLZQMFGPSYTSDYFWWDJZJYSXYYCZCYHZWPBYKXRYLYBHKJKSFXTZJMMCKHLLTNYYMSYXYZPYJQYCSYCWMTJJKQYRHLLQXPSGTLYYCLJSCPXJYZFNMLRGJJTYZBXYZMSJYJHHFZQMSYXRSZCWTLRTQZSSTKXGQKGSPTGCZNJSJCQCXHMXGGZTQYDJKZDLBZSXJLHYQGGGTHQSZPYHJHHGYYGKGGCWJZZYLCZLXQSFTGZSLLLMLJSKCTBLLZZSZMMNYTPZSXQHJCJYQXYZXZQZCPSHKZZYSXCDFGMWQRLLQXRFZTLYSTCTMJCXJJXHJNXTNRZTZFQYHQGLLGCXSZSJDJLJCYDSJTLNYXHSZXCGJZYQPYLFHDJSBPCCZHJJJQZJQDYBSSLLCMYTTMQTBHJQNNYGKYRQYQMZGCJKPDCGMYZHQLLSLLCLMHOLZGDYYFZSLJCQZLYLZQJESHNYLLJXGJXLYSYYYXNBZLJSSZCQQCJYLLZLTJYLLZLLBNYLGQCHXYYXOXCXQKYJXXXYKLXSXXYQXCYKQXQCSGYXXYQXYGYTQOHXHXPYXXXULCYEYCHZZCBWQBBWJQZSCSZSSLZYLKDESJZWMYMCYTSDSXXSCJPQQSQYLYYZYCMDJDZYWCBTJSYDJKCYDDJLBDJJSODZYSYXQQYXDHHGQQYQHDYXWGMMMAJDYBBBPPBCMUUPLJZSMTXERXJMHQNUTPJDCBSSMSSSTKJTSSMMTRCPLZSZMLQDSDMJMQPNQDXCFYNBFSDQXYXHYAYKQYDDLQYYYSSZBYDSLNTFQTZQPZMCHDHCZCWFDXTMYQSPHQYYXSRGJCWTJTZZQMGWJJTJHTQJBBHWZPXXHYQFXXQYWYYHYSCDYDHHQMNMTMWCPBSZPPZZGLMZFOLLCFWHMMSJZTTDHZZYFFYTZZGZYSKYJXQYJZQBHMBZZLYGHGFMSHPZFZSNCLPBQSNJXZSLXXFPMTYJYGBXLLDLXPZJYZJYHHZCYWHJYLSJEXFSZZYWXKZJLUYDTMLYMQJPWXYHXSKTQJEZRPXXZHHMHWQPWQLYJJQJJZSZCPHJLCHHNXJLQWZJHBMZYXBDHHYPZLHLHLGFWLCHYYTLHJXCJMSCPXSTKPNHQXSRTYXXTESYJCTLSSLSTDLLLWWYHDHRJZSFGXTSYCZYNYHTDHWJSLHTZDQDJZXXQHGYLTZPHCSQFCLNJTCLZPFSTPDYNYLGMJLLYCQHYSSHCHYLHQYQTMZYPBYWRFQYKQSYSLZDQJMPXYYSSRHZJNYWTQDFZBWWTWWRXCWHGYHXMKMYYYQMSMZHNGCEPMLQQMTCWCTMMPXJPJJHFXYYZSXZHTYBMSTSYJTTQQQYYLHYNPYQZLCYZHZWSMYLKFJXLWGXYPJYTYSYXYMZCKTTWLKSMZSYLMPWLZWXWQZSSAQSYXYRHSSNTSRAPXCPWCMGDXHXZDZYFJHGZTTSBJHGYZSZYSMYCLLLXBTYXHBBZJKSSDMALXHYCFYGMQYPJYCQXJLLLJGSLZGQLYCJCCZOTYXMTMTTLLWTGPXYMZMKLPSZZZXHKQYSXCTYJZYHXSHYXZKXLZWPSQPYHJWPJPWXQQYLXSDHMRSLZZYZWTTCYXYSZZSHBSCCSTPLWSSCJCHNLCGCHSSPHYLHFHHXJSXYLLNYLSZDHZXYLSXLWZYKCLDYAXZCMDDYSPJTQJZLNWQPSSSWCTSTSZLBLNXSMNYYMJQBQHRZWTYYDCHQLXKPZWBGQYBKFCMZWPZLLYYLSZYDWHXPSBCMLJBSCGBHXLQHYRLJXYSWXWXZSLDFHLSLYNJLZYFLYJYCDRJLFSYZFSLLCQYQFGJYHYXZLYLMSTDJCYHBZLLNWLXXYGYYHSMGDHXXHHLZZJZXCZZZCYQZFNGWPYLCPKPYYPMCLQKDGXZGGWQBDXZZKZFBXXLZXJTPJPTTBYTSZZDWSLCHZHSLTYXHQLHYXXXYYZYSWTXZKHLXZXZPYHGCHKCFSYHUTJRLXFJXPTZTWHPLYXFCRHXSHXKYXXYHZQDXQWULHYHMJTBFLKHTXCWHJFWJCFPQRYQXCYYYQYGRPYWSGSUNGWCHKZDXYFLXXHJJBYZWTSXXNCYJJYMSWZJQRMHXZWFQSYLZJZGBHYNSLBGTTCSYBYXXWXYHXYYXNSQYXMQYWRGYQLXBBZLJSYLPSYTJZYHYZAWLRORJMKSCZJXXXYXCHDYXRYXXJDTSQFXLYLTSFFYXLMTYJMJUYYYXLTZCSXQZQHZXLYYXZHDNBRXXXJCTYHLBRLMBRLLAXKYLLLJLYXXLYCRYLCJTGJCMTLZLLCYZZPZPCYAWHJJFYBDYYZSMPCKZDQYQPBPCJPDCYZMDPBCYYDYCNNPLMTMLRMFMMGWYZBSJGYGSMZQQQZTXMKQWGXLLPJGZBQCDJJJFPKJKCXBLJMSWMDTQJXLDLPPBXCWRCQFBFQJCZAHZGMYKPHYYHZYKNDKZMBPJYXPXYHLFPNYYGXJDBKXNXHJMZJXSTRSTLDXSKZYSYBZXJLXYSLBZYSLHXJPFXPQNBYLLJQKYGZMCYZZYMCCSLCLHZFWFWYXZMWSXTYNXJHPYYMCYSPMHYSMYDYSHQYZCHMJJMZCAAGCFJBBHPLYZYLXXSDJGXDHKXXTXXNBHRMLYJSLTXMRHNLXQJXYZLLYSWQGDLBJHDCGJYQYCMHWFMJYBMBYJYJWYMDPWHXQLDYGPDFXXBCGJSPCKRSSYZJMSLBZZJFLJJJLGXZGYXYXLSZQYXBEXYXHGCXBPLDYHWETTWWCJMBTXCHXYQXLLXFLYXLLJLSSFWDPZSMYJCLMWYTCZPCHQEKCQBWLCQYDPLQPPQZQFJQDJHYMMCXTXDRMJWRHXCJZYLQXDYYNHYYHRSLSRSYWWZJYMTLTLLGTQCJZYABTCKZCJYCCQLJZQXALMZYHYWLWDXZXQDLLQSHGPJFJLJHJABCQZDJGTKHSSTCYJLPSWZLXZXRWGLDLZRLZXTGSLLLLZLYXXWGDZYGBDPHZPBRLWSXQBPFDWOFMWHLYPCBJCCLDMBZPBZZLCYQXLDOMZBLZWPDWYYGDSTTHCSQSCCRSSSYSLFYBFNTYJSZDFNDPDHDZZMBBLSLCMYFFGTJJQWFTMTPJWFNLBZCMMJTGBDZLQLPYFHYYMJYLSDCHDZJWJCCTLJCLDTLJJCPDDSQDSSZYBNDBJLGGJZXSXNLYCYBJXQYCBYLZCFZPPGKCXZDZFZTJJFJSJXZBNZYJQTTYJYHTYCZHYMDJXTTMPXSPLZCDWSLSHXYPZGTFMLCJTYCBPMGDKWYCYZCDSZZYHFLYCTYGWHKJYYLSJCXGYWJCBLLCSNDDBTZBSCLYZCZZSSQDLLMQYYHFSLQLLXFTYHABXGWNYWYYPLLSDLDLLBJCYXJZMLHLJDXYYQYTDLLLBUGBFDFBBQJZZMDPJHGCLGMJJPGAEHHBWCQXAXHHHZCHXYPHJAXHLPHJPGPZJQCQZGJJZZUZDMQYYBZZPHYHYBWHAZYJHYKFGDPFQSDLZMLJXKXGALXZDAGLMDGXMWZQYXXDXXPFDMMSSYMPFMDMMKXKSYZYSHDZKXSYSMMZZZMSYDNZZCZXFPLSTMZDNMXCKJMZTYYMZMZZMSXHHDCZJEMXXKLJSTLWLSQLYJZLLZJSSDPPMHNLZJCZYHMXXHGZCJMDHXTKGRMXFWMCGMWKDTKSXQMMMFZZYDKMSCLCMPCGMHSPXQPZDSSLCXKYXTWLWJYAHZJGZQMCSNXYYMMPMLKJXMHLMLQMXCTKZMJQYSZJSYSZHSYJZJCDAJZYBSDQJZGWZQQXFKDMSDJLFWEHKZQKJPEYPZYSZCDWYJFFMZZYLTTDZZEFMZLBNPPLPLPEPSZALLTYLKCKQZKGENQLWAGYXYDPXLHSXQQWQCQXQCLHYXXMLYCCWLYMQYSKGCHLCJNSZKPYZKCQZQLJPDMDZHLASXLBYDWQLWDNBQCRYDDZTJYBKBWSZDXDTNPJDTCTQDFXQQMGNXECLTTBKPWSLCTYQLPWYZZKLPYGZCQQPLLKCCYLPQMZCZQCLJSLQZDJXLDDHPZQDLJJXZQDXYZQKZLJCYQDYJPPYPQYKJYRMPCBYMCXKLLZLLFQPYLLLMBSGLCYSSLRSYSQTMXYXZQZFDZUYSYZTFFMZZSMZQHZSSCCMLYXWTPZGXZJGZGSJSGKDDHTQGGZLLBJDZLCBCHYXYZHZFYWXYZYMSDBZZYJGTSMTFXQYXQSTDGSLNXDLRYZZLRYYLXQHTXSRTZNGZXBNQQZFMYKMZJBZYMKBPNLYZPBLMCNQYZZZSJZHJCTZKHYZZJRDYZHNPXGLFZTLKGJTCTSSYLLGZRZBBQZZKLPKLCZYSSUYXBJFPNJZZXCDWXZYJXZZDJJKGGRSRJKMSMZJLSJYWQSKYHQJSXPJZZZLSNSHRNYPZTWCHKLPSRZLZXYJQXQKYSJYCZTLQZYBBYBWZPQDWWYZCYTJCJXCKCWDKKZXSGKDZXWWYYJQYYTCYTDLLXWKCZKKLCCLZCQQDZLQLCSFQCHQHSFSMQZZLNBJJZBSJHTSZDYSJQJPDLZCDCWJKJZZLPYCGMZWDJJBSJQZSYZYHHXJPBJYDSSXDZNCGLQMBTSFSBPDZDLZNFGFJGFSMPXJQLMBLGQCYYXBQKDJJQYRFKZTJDHCZKLBSDZCFJTPLLJGXHYXZCSSZZXSTJYGKGCKGYOQXJPLZPBPGTGYJZGHZQZZLBJLSQFZGKQQJZGYCZBZQTLDXRJXBSXXPZXHYZYCLWDXJJHXMFDZPFZHQHQMQGKSLYHTYCGFRZGNQXCLPDLBZCSCZQLLJBLHBZCYPZZPPDYMZZSGYHCKCPZJGSLJLNSCDSLDLXBMSTLDDFJMKDJDHZLZXLSZQPQPGJLLYBDSZGQLBZLSLKYYHZTTNTJYQTZZPSZQZTLLJTYYLLQLLQYZQLBDZLSLYYZYMDFSZSNHLXZNCZQZPBWSKRFBSYZMTHBLGJPMCZZLSTLXSHTCSYZLZBLFEQHLXFLCJLYLJQCBZLZJHHSSTBRMHXZHJZCLXFNBGXGTQJCZTMSFZKJMSSNXLJKBHSJXNTNLZDNTLMSJXGZJYJCZXYJYJWRWWQNZTNFJSZPZSHZJFYRDJSFSZJZBJFZQZZHZLXFYSBZQLZSGYFTZDCSZXZJBQMSZKJRHYJZCKMJKHCHGTXKXQGLXPXFXTRTYLXJXHDTSJXHJZJXZWZLCQSBTXWXGXTXXHXFTSDKFJHZYJFJXRZSDLLLTQSQQZQWZXSYQTWGWBZCGZLLYZBCLMQQTZHZXZXLJFRMYZFLXYSQXXJKXRMQDZDMMYYBSQBHGZMWFWXGMXLZPYYTGZYCCDXYZXYWGSYJYZNBHPZJSQSYXSXRTFYZGRHZTXSZZTHCBFCLSYXZLZQMZLMPLMXZJXSFLBYZMYQHXJSXRXSQZZZSSLYFRCZJRCRXHHZXQYDYHXSJJHZCXZBTYNSYSXJBQLPXZQPYMLXZKYXLXCJLCYSXXZZLXDLLLJJYHZXGYJWKJRWYHCPSGNRZLFZWFZZNSXGXFLZSXZZZBFCSYJDBRJKRDHHGXJLJJTGXJXXSTJTJXLYXQFCSGSWMSBCTLQZZWLZZKXJMLTMJYHSDDBXGZHDLBMYJFRZFSGCLYJBPMLYSMSXLSZJQQHJZFXGFQFQBPXZGYYQXGZTCQWYLTLGWSGWHRLFSFGZJMGMGBGTJFSYZZGZYZAFLSSPMLPFLCWBJZCLJJMZLPJJLYMQDMYYYFBGYGYZMLYZDXQYXRQQQHSYYYQXYLJTYXFSFSLLGNQCYHYCWFHCCCFXPYLYPLLZYXXXXXKQHHXSHJZCFZSCZJXCPZWHHHHHAPYLQALPQAFYHXDYLUKMZQGGGDDESRNNZLTZGCHYPPYSQJJHCLLJTOLNJPZLJLHYMHEYDYDSQYCDDHGZUNDZCLZYZLLZNTNYZGSLHSLPJJBDGWXPCDUTJCKLKCLWKLLCASSTKZZDNQNTTLYYZSSYSSZZRYLJQKCQDHHCRXRZYDGRGCWCGZQFFFPPJFZYNAKRGYWYQPQXXFKJTSZZXSWZDDFBBXTBGTZKZNPZZPZXZPJSZBMQHKCYXYLDKLJNYPKYGHGDZJXXEAHPNZKZTZCMXCXMMJXNKSZQNMNLWBWWXJKYHCPSTMCSQTZJYXTPCTPDTNNPGLLLZSJLSPBLPLQHDTNJNLYYRSZFFJFQWDPHZDWMRZCCLODAXNSSNYZRESTYJWJYJDBCFXNMWTTBYLWSTSZGYBLJPXGLBOCLHPCBJLTMXZLJYLZXCLTPNCLCKXTPZJSWCYXSFYSZDKNTLBYJCYJLLSTGQCBXRYZXBXKLYLHZLQZLNZCXWJZLJZJNCJHXMNZZGJZZXTZJXYCYYCXXJYYXJJXSSSJSTSSTTPPGQTCSXWZDCSYFPTFBFHFBBLZJCLZZDBXGCXLQPXKFZFLSYLTUWBMQJHSZBMDDBCYSCCLDXYCDDQLYJJWMQLLCSGLJJSYFPYYCCYLTJANTJJPWYCMMGQYYSXDXQMZHSZXPFTWWZQSWQRFKJLZJQQYFBRXJHHFWJJZYQAZMYFRHCYYBYQWLPEXCCZSTYRLTTDMQLYKMBBGMYYJPRKZNPBSXYXBHYZDJDNGHPMFSGMWFZMFQMMBCMZZCJJLCNUXYQLMLRYGQZCYXZLWJGCJCGGMCJNFYZZJHYCPRRCMTZQZXHFQGTJXCCJEAQCRJYHPLQLSZDJRBCQHQDYRHYLYXJSYMHZYDWLDFRYHBPYDTSSCNWBXGLPZMLZZTQSSCPJMXXYCSJYTYCGHYCJWYRXXLFEMWJNMKLLSWTXHYYYNCMMCWJDQDJZGLLJWJRKHPZGGFLCCSCZMCBLTBHBQJXQDSPDJZZGKGLFQYWBZYZJLTSTDHQHCTCBCHFLQMPWDSHYYTQWCNZZJTLBYMBPDYYYXSQKXWYYFLXXNCWCXYPMAELYKKJMZZZBRXYYQJFLJPFHHHYTZZXSGQQMHSPGDZQWBWPJHZJDYSCQWZKTXXSQLZYYMYSDZGRXCKKUJLWPYSYSCSYZLRMLQSYLJXBCXTLWDQZPCYCYKPPPNSXFYZJJRCEMHSZMSXLXGLRWGCSTLRSXBZGBZGZTCPLUJLSLYLYMTXMTZPALZXPXJTJWTCYYZLBLXBZLQMYLXPGHDSLSSDMXMBDZZSXWHAMLCZCPJMCNHJYSNSYGCHSKQMZZQDLLKABLWJXSFMOCDXJRRLYQZKJMYBYQLYHETFJZFRFKSRYXFJTWDSXXSYSQJYSLYXWJHSNLXYYXHBHAWHHJZXWMYLJCSSLKYDZTXBZSYFDXGXZJKHSXXYBSSXDPYNZWRPTQZCZENYGCXQFJYKJBZMLJCMQQXUOXSLYXXLYLLJDZBTYMHPFSTTQQWLHOKYBLZZALZXQLHZWRRQHLSTMYPYXJJXMQSJFNBXYXYJXXYQYLTHYLQYFMLKLJTMLLHSZWKZHLJMLHLJKLJSTLQXYLMBHHLNLZXQJHXCFXXLHYHJJGBYZZKBXSCQDJQDSUJZYYHZHHMGSXCSYMXFEBCQWWRBPYYJQTYZCYQYQQZYHMWFFHGZFRJFCDPXNTQYZPDYKHJLFRZXPPXZDBBGZQSTLGDGYLCQMLCHHMFYWLZYXKJLYPQHSYWMQQGQZMLZJNSQXJQSYJYCBEHSXFSZPXZWFLLBCYYJDYTDTHWZSFJMQQYJLMQXXLLDTTKHHYBFPWTYYSQQWNQWLGWDEBZWCMYGCULKJXTMXMYJSXHYBRWFYMWFRXYQMXYSZTZZTFYKMLDHQDXWYYNLCRYJBLPSXCXYWLSPRRJWXHQYPHTYDNXHHMMYWYTZCSQMTSSCCDALWZTCPQPYJLLQZYJSWXMZZMMYLMXCLMXCZMXMZSQTZPPQQBLPGXQZHFLJJHYTJSRXWZXSCCDLXTYJDCQJXSLQYCLZXLZZXMXQRJMHRHZJBHMFLJLMLCLQNLDXZLLLPYPSYJYSXCQQDCMQJZZXHNPNXZMEKMXHYKYQLXSXTXJYYHWDCWDZHQYYBGYBCYSCFGPSJNZDYZZJZXRZRQJJYMCANYRJTLDPPYZBSTJKXXZYPFDWFGZZRPYMTNGXZQBYXNBUFNQKRJQZMJEGRZGYCLKXZDSKKNSXKCLJSPJYYZLQQJYBZSSQLLLKJXTBKTYLCCDDBLSPPFYLGYDTZJYQGGKQTTFZXBDKTYYHYBBFYTYYBCLPDYTGDHRYRNJSPTCSNYJQHKLLLZSLYDXXWBCJQSPXBPJZJCJDZFFXXBRMLAZHCSNDLBJDSZBLPRZTSWSBXBCLLXXLZDJZSJPYLYXXYFTFFFBHJJXGBYXJPMMMPSSJZJMTLYZJXSWXTYLEDQPJMYGQZJGDJLQJWJQLLSJGJGYGMSCLJJXDTYGJQJQJCJZCJGDZZSXQGSJGGCXHQXSNQLZZBXHSGZXCXYLJXYXYYDFQQJHJFXDHCTXJYRXYSQTJXYEFYYSSYYJXNCYZXFXMSYSZXYYSCHSHXZZZGZZZGFJDLTYLNPZGYJYZYYQZPBXQBDZTZCZYXXYHHSQXSHDHGQHJHGYWSZTMZMLHYXGEBTYLZKQWYTJZRCLEKYSTDBCYKQQSAYXCJXWWGSBHJYZYDHCSJKQCXSWXFLTYNYZPZCCZJQTZWJQDZZZQZLJJXLSBHPYXXPSXSHHEZTXFPTLQYZZXHYTXNCFZYYHXGNXMYWXTZSJPTHHGYMXMXQZXTSBCZYJYXXTYYZYPCQLMMSZMJZZLLZXGXZAAJZYXJMZXWDXZSXZDZXLEYJJZQBHZWZZZQTZPSXZTDSXJJJZNYAZPHXYYSRNQDTHZHYYKYJHDZXZLSWCLYBZYECWCYCRYLCXNHZYDZYDYJDFRJJHTRSQTXYXJRJHOJYNXELXSFSFJZGHPZSXZSZDZCQZBYYKLSGSJHCZSHDGQGXYZGXCHXZJWYQWGYHKSSEQZZNDZFKWYSSTCLZSTSYMCDHJXXYWEYXCZAYDMPXMDSXYBSQMJMZJMTZQLPJYQZCGQHXJHHLXXHLHDLDJQCLDWBSXFZZYYSCHTYTYYBHECXHYKGJPXHHYZJFXHWHBDZFYZBCAPNPGNYDMSXHMMMMAMYNBYJTMPXYYMCTHJBZYFCGTYHWPHFTWZZEZSBZEGPFMTSKFTYCMHFLLHGPZJXZJGZJYXZSBBQSCZZLZCCSTPGXMJSFTCCZJZDJXCYBZLFCJSYZFGSZLYBCWZZBYZDZYPSWYJZXZBDSYUXLZZBZFYGCZXBZHZFTPBGZGEJBSTGKDMFHYZZJHZLLZZGJQZLSFDJSSCBZGPDLFZFZSZYZYZSYGCXSNXXCHCZXTZZLJFZGQSQYXZJQDCCZTQCDXZJYQJQCHXZTDLGSCXZSYQJQTZWLQDQZTQCHQQJZYEZZZPBWKDJFCJPZTYPQYQTTYNLMBDKTJZPQZQZZFPZSBNJLGYJDXJDZZKZGQKXDLPZJTCJDQBXDJQJSTCKNXBXZMSLYJCQMTJQWWCJQNJNLLLHJCWQTBZQYDZCZPZZDZYDDCYZZZCCJTTJFZDPRRTZTJDCQTQZDTJNPLZBCLLCTZSXKJZQZPZLBZRBTJDCXFCZDBCCJJLTQQPLDCGZDBBZJCQDCJWYNLLZYZCCDWLLXWZLXRXNTQQCZXKQLSGDFQTDDGLRLAJJTKUYMKQLLTZYTDYYCZGJWYXDXFRSKSTQTENQMRKQZHHQKDLDAZFKYPBGGPZREBZZYKZZSPEGJXGYKQZZZSLYSYYYZWFQZYLZZLZHWCHKYPQGNPGBLPLRRJYXCCSYYHSFZFYBZYYTGZXYLXCZWXXZJZBLF***SKHYJZEYJHLPLLLLCZGXDRZELRHGKLZZYHZLYQSZZJZQLJZFLNBHGWLCZCFJYSPYXZLZLXGCCPZBLLCYBBBBUBBCBPCRNNZCZYRBFSRLDCGQYYQXYGMQZWTZYTYJXYFWTEHZZJYWLCCNTZYJJZDEDPZDZTSYQJHDYMBJNYJZLXTSSTPHNDJXXBYXQTZQDDTJTDYYTGWSCSZQFLSHLGLBCZPHDLYZJYCKWTYTYLBNYTSDSYCCTYSZYYEBHEXHQDTWNYGYCLXTSZYSTQMYGZAZCCSZZDSLZCLZRQXYYELJSBYMXSXZTEMBBLLYYLLYTDQYSHYMRQWKFKBFXNXSBYCHXBWJYHTQBPBSBWDZYLKGZSKYHXQZJXHXJXGNLJKZLYYCDXLFYFGHLJGJYBXQLYBXQPQGZTZPLNCYPXDJYQYDYMRBESJYYHKXXSTMXRCZZYWXYQYBMCLLYZHQYZWQXDBXBZWZMSLPDMYSKFMZKLZCYQYCZLQXFZZYDQZPZYGYJYZMZXDZFYFYTTQTZHGSPCZMLCCYTZXJCYTJMKSLPZHYSNZLLYTPZCTZZCKTXDHXXTQCYFKSMQCCYYAZHTJPCYLZLYJBJXTPNYLJYYNRXSYLMMNXJSMYBCSYSYLZYLXJJQYLDZLPQBFZZBLFNDXQKCZFYWHGQMRDSXYCYTXNQQJZYYPFZXDYZFPRXEJDGYQBXRCNFYYQPGHYJDYZXGRHTKYLNWDZNTSMPKLBTHBPYSZBZTJZSZZJTYYXZPHSSZZBZCZPTQFZMYFLYPYBBJQXZMXXDJMTSYSKKBJZXHJCKLPSMKYJZCXTMLJYXRZZQSLXXQPYZXMKYXXXJCLJPRMYYGADYSKQLSNDHYZKQXZYZTCGHZTLMLWZYBWSYCTBHJHJFCWZTXWYTKZLXQSHLYJZJXTMPLPYCGLTBZZTLZJCYJGDTCLKLPLLQPJMZPAPXYZLKKTKDZCZZBNZDYDYQZJYJGMCTXLTGXSZLMLHBGLKFWNWZHDXUHLFMKYSLGXDTWWFRJEJZTZHYDXYKSHWFZCQSHKTMQQHTZHYMJDJSKHXZJZBZZXYMPAGQMSTPXLSKLZYNWRTSQLSZBPSPSGZWYHTLKSSSWHZZLYYTNXJGMJSZSUFWNLSOZTXGXLSAMMLBWLDSZYLAKQCQCTMYCFJBSLXCLZZCLXXKSBZQCLHJPSQPLSXXCKSLNHPSFQQYTXYJZLQLDXZQJZDYYDJNZPTUZDSKJFSLJHYLZSQZLBTXYDGTQFDBYAZXDZHZJNHHQBYKNXJJQCZMLLJZKSPLDYCLBBLXKLELXJLBQYCXJXGCNLCQPLZLZYJTZLJGYZDZPLTQCSXFDMNYCXGBTJDCZNBGBQYQJWGKFHTNPYQZQGBKPBBYZMTJDYTBLSQMPSXTBNPDXKLEMYYCJYNZCTLDYKZZXDDXHQSHDGMZSJYCCTAYRZLPYLTLKXSLZCGGEXCLFXLKJRTLQJAQZNCMBYDKKCXGLCZJZXJHPTDJJMZQYKQSECQZDSHHADMLZFMMZBGNTJNNLGBYJBRBTMLBYJDZXLCJLPLDLPCQDHLXZLYCBLCXZZJADJLNZMMSSSMYBHBSQKBHRSXXJMXSDZNZPXLGBRHWGGFCXGMSKLLTSJYYCQLTSKYWYYHYWXBXQYWPYWYKQLSQPTNTKHQCWDQKTWPXXHCPTHTWUMSSYHBWCRWXHJMKMZNGWTMLKFGHKJYLSYYCXWHYECLQHKQHTTQKHFZLDXQWYZYYDESBPKYRZPJFYYZJCEQDZZDLATZBBFJLLCXDLMJSSXEGYGSJQXCWBXSSZPDYZCXDNYXPPZYDLYJCZPLTXLSXYZYRXCYYYDYLWWNZSAHJSYQYHGYWWAXTJZDAXYSRLTDPSSYYFNEJDXYZHLXLLLZQZSJNYQYQQXYJGHZGZCYJCHZLYCDSHWSHJZYJXCLLNXZJJYYXNFXMWFPYLCYLLABWDDHWDXJMCXZTZPMLQZHSFHZYNZTLLDYWLSLXHYMMYLMBWWKYXYADTXYLLDJPYBPWUXJMWMLLSAFDLLYFLBHHHBQQLTZJCQJLDJTFFKMMMBYTHYGDCQRDDWRQJXNBYSNWZDBYYTBJHPYBYTTJXAAHGQDQTMYSTQXKBTZPKJLZRBEQQSSMJJBDJOTGTBXPGBKTLHQXJJJCTHXQDWJLWRFWQGWSHCKRYSWGFTGYGBXSDWDWRFHWYTJJXXXJYZYSLPYYYPAYXHYDQKXSHXYXGSKQHYWFDDDPPLCJLQQEEWXKSYYKDYPLTJTHKJLTCYYHHJTTPLTZZCDLTHQKZXQYSTEEYWYYZYXXYYSTTJKLLPZMCYHQGXYHSRMBXPLLNQYDQHXSXXWGDQBSHYLLPJJJTHYJKYPPTHYYKTYEZYENMDSHLCRPQFDGFXZPSFTLJXXJBSWYYSKSFLXLPPLBBBLBSFXFYZBSJSSYLPBBFFFFSSCJDSTZSXZRYYSYFFSYZYZBJTBCTSBSDHRTJJBYTCXYJEYLXCBNEBJDSYXYKGSJZBXBYTFZWGENYHHTHZHHXFWGCSTBGXKLSXYWMTMBYXJSTZSCDYQRCYTWXZFHMYMCXLZNSDJTTTXRYCFYJSBSDYERXJLJXBBDEYNJGHXGCKGSCYMBLXJMSZNSKGXFBNBPTHFJAAFXYXFPXMYPQDTZCXZZPXRSYWZDLYBBKTYQPQJPZYPZJZNJPZJLZZFYSBTTSLMPTZRTDXQSJEHBZYLZDHLJSQMLHTXTJECXSLZZSPKTLZKQQYFSYGYWPCPQFHQHYTQXZKRSGTTSQCZLPTXCDYYZXSQZSLXLZMYCPCQBZYXHBSXLZDLTCDXTYLZJYYZPZYZLTXJSJXHLPMYTXCQRBLZSSFJZZTNJYTXMYJHLHPPLCYXQJQQKZZSCPZKSWALQSBLCCZJSXGWWWYGYKTJBBZTDKHXHKGTGPBKQYSLPXPJCKBMLLXDZSTBKLGGQKQLSBKKTFXRMDKBFTPZFRTBBRFERQGXYJPZSSTLBZTPSZQZSJDHLJQLZBPMSMMSXLQQNHKNBLRDDNXXDHDDJCYYGYLXGZLXSYGMQQGKHBPMXYXLYTQWLWGCPBMQXCYZYDRJBHTDJYHQSHTMJSBYPLWHLZFFNYPMHXXHPLTBQPFBJWQDBYGPNZTPFZJGSDDTQSHZEAWZZYLLTYYBWJKXXGHLFKXDJTMSZSQYNZGGSWQSPHTLSSKMCLZXYSZQZXNCJDQGZDLFNYKLJCJLLZLMZZNHYDSSHTHZZLZZBBHQZWWYCRZHLYQQJBEYFXXXWHSRXWQHWPSLMSSKZTTYGYQQWRSLALHMJTQJSMXQBJJZJXZYZKXBYQXBJXSHZTSFJLXMXZXFGHKZSZGGYLCLSARJYHSLLLMZXELGLXYDJYTLFBHBPNLYZFBBHPTGJKWETZHKJJXZXXGLLJLSTGSHJJYQLQZFKCGNNDJSSZFDBCTWWSEQFHQJBSAQTGYPQLBXBMMYWXGSLZHGLZGQYFLZBYFZJFRYSFMBYZHQGFWZSYFYJJPHZBYYZFFWODGRLMFTWLBZGYCQXCDJYGZYYYYTYTYDWEGAZYHXJLZYYHLRMGRXXZCLHNELJJTJTPWJYBJJBXJJTJTEEKHWSLJPLPSFYZPQQBDLQJJTYYQLYZKDKSQJYYQZLDQTGJQYZJSUCMRYQTHTEJMFCTYHYPKMHYZWJDQFHYYXWSHCTXRLJHQXHCCYYYJLTKTTYTMXGTCJTZAYYOCZLYLBSZYWJYTSJYHBYSHFJLYGJXXTMZYYLTXXYPZLXYJZYZYYPNHMYMDYYLBLHLSYYQQLLNJJYMSOYQBZGDLYXYLCQYXTSZEGXHZGLHWBLJHEYXTWQMAKBPQCGYSHHEGQCMWYYWLJYJHYYZLLJJYLHZYHMGSLJLJXCJJYCLYCJPCPZJZJMMYLCQLNQLJQJSXYJMLSZLJQLYCMMHCFMMFPQQMFYLQMCFFQMMMMHMZNFHHJGTTHHKHSLNCHHYQDXTMMQDCYZYXYQMYQYLTDCYYYZAZZCYMZYDLZFFFMMYCQZWZZMABTBYZTDMNZZGGDFTYPCGQYTTSSFFWFDTZQSSYSTWXJHXYTSXXYLBYQHWWKXHZXWZNNZZJZJJQJCCCHYYXBZXZCYZTLLCQXYNJYCYYCYNZZQYYYEWYCZDCJYCCHYJLBTZYYCQWMPWPYMLGKDLDLGKQQBGYCHJXY";
  String.prototype.getCharSpellLetter = function(idx) {
    /// <summary>获取中文字符在中文字符编码表中的拼音首字母，如果不是中文则直接返回字符本身</summary>
    /// <param name="char" type="String">中文字符</param>
    /// <returns type="String" />
    var charCode = this.charCodeAt(idx || 0);
    if (charCode >= chineseCharStartIndex) {
      return chineseCharSpellLetterTable.charAt(
        charCode - chineseCharStartIndex
      );
    }
    return "";
  };

  String.prototype.map = function(fun, thisObj) {
    var res = [];
    var isFun = fun && fun.IsFunction;
    for (var i = 0; i < this.length; i++) {
      let val = this[i];
      if (isFun) {
        val = fun.call(thisObj, val, i, this.charCodeAt(i));
      }
      res.push(val);
    }
    return res;
  };

  String.prototype.formatWith = function(
    splitChar,
    intervalNum,
    ignoreChar,
    resetIgnoreCounter,
    reverse
  ) {
    /// <summary>将当前字符串按指定字符串和指定长度的间隔格式化，比如 13888888888 按“ ”字符间隔4个长度格式化成138 8888 8888</summary>
    /// <param name="splitChar" type="String">分割字符，默认空格</param>
    /// <param name="intervalNum" type="Number">分割长度，默认4</param>
    /// <param name="ignoreChar" type="String">需要忽略的字符，如果遇到忽略的字符，如果resetIgnoreCounter为true,则长度计数重置为0</param>
    /// <param name="resetIgnoreCounter" type="Boolean">遇到ignoreChar字符时，是否重置间隔计数</param>
    /// <param name="reverse" type="Boolean">是否倒序，默认true</param>
    splitChar = splitChar || " ";
    intervalNum = intervalNum > 0 ? intervalNum : 4;
    reverse = Object.ifNullOrEmpty(reverse, true);
    var chars = this.split("");
    var result = [];
    var idx = 0;
    var func = function(char) {
      reverse ? result.insert(0, char) : result.push(char);
      idx++;
      if (char != ignoreChar) {
        idx % intervalNum == 0 &&
          (reverse ? result.insert(0, splitChar) : result.push(splitChar));
      } else if (resetIgnoreCounter) {
        idx = 0;
      }
    };
    reverse ? chars.forEachReverse(func) : chars.forEach(func);
    result[0] == splitChar && result.remove(0);
    return result.join("");
  };

  String.prototype.toDateString = function(format) {
    /// <summary>将当前字符串转换成日期类型，并格式化成指定格式的日期字符串</summary>
    if (Object.isNullOrEmpty(this)) {
      return "";
    }
    var date = this.toDate();
    return date ? date.toDateString(format) : "";
  };

  String.prototype.endIndexOf = function(find) {
    /// <summary>查找指定字符串在当前字符串中的结束位置</summary>
    if (Object.isNullOrEmpty(find)) {
      return -1;
    }
    var idx = this.indexOf(find);
    return idx >= 0 ? this.indexOf(find) + find.length : -1;
  };

  String.prototype.endIndexOfAny = function() {
    /// <summary>查找任意指定字符串在当前字符串中的结束位置</summary>
    var arr = Array.prototype.concat.call([], arguments);
    var idx = -1;
    for (var i = 0; i < arguments.length; i++) {
      var idx = this.endIndexOf(arguments[i]);
      if (idx > 0) {
        return idx;
      }
    }
    return -1;
  };

  String.DATE_PATTERN = new RegExp(
    "^(\\d{4})[-|年|/|\\.](\\d{1,2})?[-|月|/|\\.]?(\\d{1,2})?日?$"
  );
  String.prototype.toDate = function() {
    /// <summary>将字符串转换成日期类型</summary>
    if (!this) {
      return "";
    }
    try {
      var timeStrPos;
      var timeStr;
      var date = new Date(1990, 01, 01);
      var datePat = String.DATE_PATTERN;
      var dateStr = this.replace(/[TZ]/gi, " ");

      timeStrPos = dateStr.indexOf(" ");
      if (timeStrPos < 0) {
        timeStrPos = dateStr.indexOf("T");
      }
      if (timeStrPos > 0) {
        timeStr = dateStr.substring(timeStrPos + 1);
        dateStr = dateStr.substring(0, timeStrPos);
        var times;

        times = timeStr.split(":");
        date.setHours(times[0], times[1], times[2] ? times[2] : 0);
      }
      if (datePat.length <= 8) {
        debugger;
      }
      var matchArray = dateStr.match(datePat);
      var year = 1900;
      var month = 0;
      var day = 1;
      year = matchArray[1];
      month = Number(matchArray[2]) > 1 ? Number(matchArray[2]) - 1 : month;
      day = Number(matchArray[3]) > 0 ? Number(matchArray[3]) : day;
      date.setYear(year);
      date.setMonth(month);
      date.setDate(day);
      return date;
    } catch (e) {
      return "";
    }
  };

  String.prototype.toGeomPolygon = function() {
    /// <summary>将WKT规范的字符串转换成Polygon对象</summary>
    if (this.indexOf("MULTIPOLYGON") >= 0) {
      var wkt = this.trim();
      wkt = wkt
        .substr(0, wkt.lastIndexOf(")"))
        .replace(/MULTIPOLYGON *?\(/gi, "");
      var arr = wkt.split(/ *\) *\) *, *\( *\(/);
      arr = arr.map(function(val) {
        return [
          val
            .replace(/(\(\(|\)\))/gi, "")
            .trim()
            .split(",")
            .map(function(m) {
              return [m.trim().split(" ")];
            })
        ];
      });
      return arr;
    } else if (this.indexOf("POLYGON") >= 0) {
      var arr = this.trim()
        .replace(/POLYGON *?/gi, "")
        .replace(/\(\(|\)\)/gi, "")
        .replace(/\), *\(/gi, ",")
        .trim()
        .split(",");
      return arr.map(function(n) {
        return [
          n
            .Trim()
            .split(" ")
            .map(function(m) {
              return parseFloat(m);
            })
        ];
      });
    }
    return null;
  };

  String.prototype.toGeomPoint = function() {
    /// <summary>将WKT规范的字符串转换成Point对象</summary>
    if (this.indexOf("POINT") >= 0) {
      return this.trim()
        .replace(/POINT *?/gi, "")
        .replace(/\(|\)/gi, "")
        .trim()
        .split(" ");
    } else if (this.indexOf(" ") > 0) {
      return this.split(" ");
    }
    return null;
  };

  String.prototype.toGeom = function() {
    /// <summary>将WKT规范的字符串转换成对象</summary>
    var polygon = this.toGeomPolygon();
    if (polygon) {
      return polygon;
    }
    return this.toGeomPoint();
  };

  String.prototype.startWiths = function() {
    /// <summary>判断当前字符串是否以指定字符串开始，支持多个字符串比较</summary>
    /// <returns type="Boolean" />
    if (!arguments.length) {
      return true;
    }
    var str = this.trim();
    if (str == "") {
      return false;
    }
    for (var i = 0; i < arguments.length; i++) {
      var exp = arguments[i];
      if (exp != null && exp) {
        exp = exp.toString();
        var strTmp = str.substr(0, exp.length);
        if (strTmp == exp) {
          return true;
        }
      }
    }
    return false;
  };

  String.prototype.endWiths = function(exp) {
    /// <summary>判断当前字符串是否以指定字符结束</summary>
    /// <param name="exp" type="String">要匹配的字符串</param>
    /// <returns type="Boolean" />
    if (!arguments.length) {
      return true;
    }
    var str = this.trim();
    if (str == "") {
      return false;
    }
    for (var i = 0; i < arguments.length; i++) {
      var exp = arguments[i];
      if (exp != null && exp) {
        exp = exp.toString();
        var strTmp = str.substr(str.length - exp.length, exp.length);
        if (strTmp == exp) {
          return true;
        }
      }
    }
    return false;
  };

  String.prototype.formatPhone = function(moduleType) {
    /// <summary>格式化手机号码</summary>
    /// <returns type="String" />
    var str = this.replace(/\s/g, "");
    moduleType = moduleType ? moduleType : "text";
    if (moduleType == "input") {
      var len = str.length;
      if (len <= 3) {
        return str;
      } else if (len > 3 && len < 7) {
        return str.substring(0, 3) + " " + str.substring(3, len);
      } else if (len <= 13) {
        return (
          str.substring(0, 3) +
          " " +
          str.substring(3, 7) +
          " " +
          str.substring(7, len)
        );
      }
    } else {
      var PHONE_NUMBER = 11;
      if (this.length < PHONE_NUMBER) {
        return this.replace(/\"/g, "");
      }
      return str.replace(/(.{3})(.{4})(.{4})/g, "$1 $2 $3");
    }
  };

  String.prototype.formatCardNo = function(moduleType) {
    /// <summary>格式化银行卡号</summary>
    /// <returns type="String" />
    var str = this.replace(/\s/g, "");
    if (moduleType == "input") {
      var len = str.length;
      if (len <= 4) {
        return str;
      } else if (len % 4 == 1) {
        return str.replace(/(.{4})/g, "$1 ");
      } else {
        return this;
      }
    } else {
      return str.replace(/(.{4})/g, "$1 ");
    }
  };

  String.prototype.removeBlank = function() {
    return this.replace(/\s/g, "");
  };

  String.__FORMAT_PATTERNS__ = [
    {
      //{***}
      startTagLength: 1,
      endTagLength: 1,
      regex: /({[^\s{}\n]*})/gi,
      test: function(exp) {
        return !/{{|}}/gi.test(exp);
      }
    },
    {
      //{{***}}
      startTagLength: 2,
      endTagLength: 2,
      regex: /({{[^\s{}\n]*}})/gi,
      test: function(exp) {
        return /{{|}}/gi.test(exp);
      }
    }
  ];

  String.__FORMAT_CACHES__ = {};
  String.prototype.format = function() {
    /// <summary>格式化指定字符串，默认支持两种标记为：{***}、{{***}}</summary>
    var handler = String.__FORMAT_CACHES__[this.toString()];
    if (!handler) {
      var expStr = this;
      var pattern = String.__FORMAT_PATTERNS__.find(function(p) {
        return p.test(expStr);
      });
      if (arguments && arguments.length > 1) {
        arguments.First = arguments[1];
        arguments.Last = arguments[arguments.length - 1];
      }
      var matchs = expStr.match(pattern.regex);
      if (Object.isNullOrEmpty(matchs)) {
        handler = function() {
          return this;
        };
      } else {
        var codes = [
          "var result = [];",
          "var value = null;",
          "var matchField = null;",
          "var expField = null;",
          "var startIndex = 0;",
          "var expFieldIndex = 0;"
        ];
        for (var i = 0; i < matchs.length; i++) {
          var expField;
          var match;

          match = matchs[i];
          if (Object.isNullOrEmpty(match)) {
            continue;
          }
          codes.push("value = null;");
          expField = match.substring(
            pattern.startTagLength,
            match.length - pattern.endTagLength
          );
          codes.push('matchField = "' + match + '";');
          codes.push('expField = "' + expField + '";');
          var errorCode =
            'console.error( "string format field [expField] error:" + e.toString() );';
          if (expField.indexOf(".") > 0) {
            //表达式中包含“.”
            if (/^\d+\./gi.test(expField)) {
              //以数字开头的表达式：0.FieldA、1.FieldB
              codes.push("value = Object.getValue( arguments, expField );");
            } else {
              //不以数字开头的表达式：window.location.href
              codes.push(
                "try{ value = " +
                  expField +
                  "; } catch ( e ) { " +
                  errorCode +
                  " }"
              );
            }
          } else if (Object.isValidNumber(expField)) {
            //表达式中不包含“.”且是数字
            codes.push(
              "try { value = arguments[" +
                expField +
                "]; } catch ( e ) { " +
                errorCode +
                " };"
            );
          } else {
            //表达式中不包含“.”也不是数字
            codes.push(
              "try { value = " +
                expField +
                "; } catch ( e ) { " +
                errorCode +
                " };"
            );
          }
          codes.push("expFieldIndex = this.indexOf( matchField, startIndex );");
          codes.push(
            "result.push( this.substring( startIndex, expFieldIndex ) );"
          );
          codes.push("result.push( value==null?'':value.toString() );");
          codes.push("startIndex = expFieldIndex + matchField.length;");
        }
        codes.push(
          "startIndex<this.length && ( result.push( this.substring(startIndex) ) );"
        );
        codes.push("return result.join('');");
        handler = new Function(codes.join("\r\n"));
      }
      String.__FORMAT_CACHES__[this] = handler;
    }
    return handler.apply(this, arguments);
  };

  String.prototype.join = function() {
    return this;
  };

  //字符串MD5
  (function() {
    /*
             * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
             * Digest Algorithm, as defined in RFC 1321.
             * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
             * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
             * Distributed under the BSD License
             * See http://pajhome.org.uk/crypt/md5 for more info.
             */

    /*
             * Configurable variables. You may need to tweak these to be compatible with
             * the server-side, but the defaults work in most cases.
             */
    var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase        */
    var b64pad =
      ""; /* base-64 pad character. "=" for strict RFC compliance   */
    var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode      */

    /*
             * These are the functions you'll usually want to call
             * They take string arguments and return either hex or base-64 encoded strings
             */
    function hex_md5(s) {
      return binl2hex(core_md5(str2binl(s), s.length * chrsz));
    }

    function b64_md5(s) {
      return binl2b64(core_md5(str2binl(s), s.length * chrsz));
    }

    function str_md5(s) {
      return binl2str(core_md5(str2binl(s), s.length * chrsz));
    }

    function hex_hmac_md5(key, data) {
      return binl2hex(core_hmac_md5(key, data));
    }

    function b64_hmac_md5(key, data) {
      return binl2b64(core_hmac_md5(key, data));
    }

    function str_hmac_md5(key, data) {
      return binl2str(core_hmac_md5(key, data));
    }

    /*
             * Perform a simple self-test to see if the VM is working
             */
    function md5_vm_test() {
      return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
    }

    /*
             * Calculate the MD5 of an array of little-endian words, and a bit length
             */
    function core_md5(x, len) {
      /* append padding */
      x[len >> 5] |= 0x80 << len % 32;
      x[(((len + 64) >>> 9) << 4) + 14] = len;

      var a = 1732584193;
      var b = -271733879;
      var c = -1732584194;
      var d = 271733878;

      for (var i = 0; i < x.length; i += 16) {
        var olda = a;
        var oldb = b;
        var oldc = c;
        var oldd = d;

        a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936);
        d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
        c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
        b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);
        a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);
        d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
        c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);
        b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);
        a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
        d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);
        c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
        b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
        a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
        d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
        c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
        b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);

        a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);
        d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);
        c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
        b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302);
        a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);
        d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
        c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
        b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);
        a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
        d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);
        c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);
        b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
        a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);
        d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);
        c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
        b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);

        a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);
        d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);
        c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
        b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
        a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);
        d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
        c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);
        b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
        a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
        d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222);
        c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);
        b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
        a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);
        d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
        c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
        b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);

        a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844);
        d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
        c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
        b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);
        a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
        d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);
        c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
        b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);
        a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
        d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
        c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);
        b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
        a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);
        d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
        c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
        b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);

        a = safe_add(a, olda);
        b = safe_add(b, oldb);
        c = safe_add(c, oldc);
        d = safe_add(d, oldd);
      }
      return Array(a, b, c, d);
    }

    /*
             * These functions implement the four basic operations the algorithm uses.
             */
    function md5_cmn(q, a, b, x, s, t) {
      return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
    }

    function md5_ff(a, b, c, d, x, s, t) {
      return md5_cmn((b & c) | (~b & d), a, b, x, s, t);
    }

    function md5_gg(a, b, c, d, x, s, t) {
      return md5_cmn((b & d) | (c & ~d), a, b, x, s, t);
    }

    function md5_hh(a, b, c, d, x, s, t) {
      return md5_cmn(b ^ c ^ d, a, b, x, s, t);
    }

    function md5_ii(a, b, c, d, x, s, t) {
      return md5_cmn(c ^ (b | ~d), a, b, x, s, t);
    }

    /*
             * Calculate the HMAC-MD5, of a key and some data
             */
    function core_hmac_md5(key, data) {
      var bkey = str2binl(key);
      if (bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz);

      var ipad = Array(16),
        opad = Array(16);
      for (var i = 0; i < 16; i++) {
        ipad[i] = bkey[i] ^ 0x36363636;
        opad[i] = bkey[i] ^ 0x5c5c5c5c;
      }

      var hash = core_md5(
        ipad.concat(str2binl(data)),
        512 + data.length * chrsz
      );
      return core_md5(opad.concat(hash), 512 + 128);
    }

    /*
             * Add integers, wrapping at 2^32. This uses 16-bit operations internally
             * to work around bugs in some JS interpreters.
             */
    function safe_add(x, y) {
      var lsw = (x & 0xffff) + (y & 0xffff);
      var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
      return (msw << 16) | (lsw & 0xffff);
    }

    /*
             * Bitwise rotate a 32-bit number to the left.
             */
    function bit_rol(num, cnt) {
      return (num << cnt) | (num >>> (32 - cnt));
    }

    /*
             * Convert a string to an array of little-endian words
             * If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
             */
    function str2binl(str) {
      var bin = Array();
      var mask = (1 << chrsz) - 1;
      for (var i = 0; i < str.length * chrsz; i += chrsz)
        bin[i >> 5] |= (str.charCodeAt(i / chrsz) & mask) << i % 32;
      return bin;
    }

    /*
             * Convert an array of little-endian words to a string
             */
    function binl2str(bin) {
      var str = "";
      var mask = (1 << chrsz) - 1;
      for (var i = 0; i < bin.length * 32; i += chrsz)
        str += String.fromCharCode((bin[i >> 5] >>> i % 32) & mask);
      return str;
    }

    /*
             * Convert an array of little-endian words to a hex string.
             */
    function binl2hex(binarray) {
      var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
      var str = "";
      for (var i = 0; i < binarray.length * 4; i++) {
        str +=
          hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8 + 4)) & 0xf) +
          hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8)) & 0xf);
      }
      return str;
    }

    /*
             * Convert an array of little-endian words to a base-64 string
             */
    function binl2b64(binarray) {
      var tab =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
      var str = "";
      for (var i = 0; i < binarray.length * 4; i += 3) {
        var triplet =
          (((binarray[i >> 2] >> (8 * (i % 4))) & 0xff) << 16) |
          (((binarray[(i + 1) >> 2] >> (8 * ((i + 1) % 4))) & 0xff) << 8) |
          ((binarray[(i + 2) >> 2] >> (8 * ((i + 2) % 4))) & 0xff);
        for (var j = 0; j < 4; j++) {
          if (i * 8 + j * 6 > binarray.length * 32) str += b64pad;
          else str += tab.charAt((triplet >> (6 * (3 - j))) & 0x3f);
        }
      }
      return str;
    }

    String.prototype.md5 = function() {
      if (Object.isNullOrEmpty(this)) {
        return null;
      }
      return hex_md5(this);
    };
  })();
})();

/****************************************Function扩展****************************************/
(function() {
  Function.DELAY_CALL_TIMEOUT_IDS = {};

  Function.callFun = function(func, thisObj) {
    /// <summary>调用指定函数 Function.callFun(func, thisObj, arg1, arg2, argn...)</summary>
    /// <param name="func" type="Function|Array">函数对象</param>
    /// <param name="thisObj" type="Object">this指向的对象</param>
    if (func) {
      var args = [];
      for (var i = 2; i < arguments.length; i++) {
        args.push(arguments[i]);
      }
      if (func.IsFunction) {
        return func.apply(thisObj, args);
      } else if (func.IsArray) {
        func.forEach(function(f) {
          if (f && f.apply) {
            var r = f.apply(thisObj, args);
            if (r == false) {
              return false;
            }
          }
        });
      }
    }
    return true;
  };

  Function.delayCall = function(name, delay, callback, thisObj) {
    /// <summary>函数延时不重复调用</summary>
    /// <param name="name" type="String">标识名称</param>
    /// <param name="delay" type="Int32">延时时间（ms）</param>
    /// <param name="callback" type="Function">回调函数</param>
    /// <param name="thisObj" type="String">回调函数的this对象</param>
    Function.clearDelayCall(name);
    var params = [callback, thisObj].concat(
      Array.prototype.slice.call(arguments, 4)
    );
    var timeOutId = (Function.DELAY_CALL_TIMEOUT_IDS[name] = setTimeout(
      function() {
        Function.callFun.apply(null, params);
        delete Function.DELAY_CALL_TIMEOUT_IDS[name];
      },
      delay
    ));
    return timeOutId;
  };

  Function.clearDelayCall = function(name) {
    /// <summary>清除延时</summary>
    var timeOutId = Function.DELAY_CALL_TIMEOUT_IDS[name];
    if (timeOutId < 0 || timeOutId > 0) {
      clearTimeout(timeOutId);
      delete Function.DELAY_CALL_TIMEOUT_IDS[name];
    }
  };

  Function.prototype.conditionalCall = function(
    callback,
    conditionFunc,
    interval
  ) {
    /// <summary>满足conditionFunc返回为true时，延时指定时间执行callback回调</summary>
    /// <param name="callback" type="Function">回调函数</param>
    /// <param name="conditionFunc" type="Function">条件检测函数</param>
    /// <param name="interval" type="Int32">延时毫秒，默认1ms</param>
    /// <returns type="Function" />
    interval = Object.isValidNumber(interval) ? interval : 10;
    var timeoutId = setTimeout(function() {
      if (conditionFunc()) {
        Function.callFun(callback);
        timeoutId = 0;
        return;
      }
      timeoutId = setTimeout(arguments.callee, interval);
    }, interval);
    //返回取消执行的回调函数
    return function() {
      if (timeoutId != 0) {
        clearTimeout(timeoutId);
        timeoutId = 0;
      }
    };
  };

  Function.getParams = function(fun, args) {
    if (arguments.length == 1) {
      args = fun;
      fun = fun.callee;
    }
    if (!args || !args.length) {
      return {};
    }
    if (args.length == 1 && args[0] && !args[0].IsString) {
      return args[0];
    }
    var funString = fun.toString();
    if (!funString) {
      return {};
    }
    var pattern = /\(([^{]*)\)/;
    var matchArr = funString.match(pattern);
    var paramStr = matchArr[0];
    if (!paramStr) {
      return {};
    }
    var paramArr = paramStr.replace(/\(|\)/gi, "").split(",");
    var paramObj = {};
    paramArr.forEach(function(name, idx) {
      paramObj[name.trim()] = args[idx];
    });
    return paramObj;
  };
})();
